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/. */
7 #include "mozilla/dom/ReadableByteStreamController.h"
9 #include "ReadIntoRequest.h"
10 #include "js/ArrayBuffer.h"
11 #include "js/ErrorReport.h"
12 #include "js/Exception.h"
13 #include "js/TypeDecls.h"
15 #include "js/ValueArray.h"
16 #include "js/experimental/TypedData.h"
17 #include "js/friend/ErrorMessages.h"
18 #include "mozilla/AlreadyAddRefed.h"
19 #include "mozilla/Attributes.h"
20 #include "mozilla/ErrorResult.h"
21 #include "mozilla/HoldDropJSObjects.h"
22 #include "mozilla/dom/ByteStreamHelpers.h"
23 #include "mozilla/dom/Promise.h"
24 #include "mozilla/dom/Promise-inl.h"
25 #include "mozilla/dom/ReadableByteStreamControllerBinding.h"
26 #include "mozilla/dom/ReadableStream.h"
27 #include "mozilla/dom/ReadableStreamBYOBReader.h"
28 #include "mozilla/dom/ReadableStreamBYOBRequest.h"
29 #include "mozilla/dom/ReadableStreamController.h"
30 #include "mozilla/dom/ReadableStreamDefaultController.h"
31 #include "mozilla/dom/ReadableStreamDefaultReader.h"
32 #include "mozilla/dom/ReadableStreamGenericReader.h"
33 #include "mozilla/dom/ToJSValue.h"
34 #include "mozilla/dom/ScriptSettings.h"
35 #include "mozilla/dom/UnderlyingSourceCallbackHelpers.h"
36 #include "nsCycleCollectionParticipant.h"
37 #include "nsIGlobalObject.h"
38 #include "nsISupports.h"
40 #include <algorithm> // std::min
42 namespace mozilla::dom
{
44 using namespace streams_abstract
;
46 NS_IMPL_CYCLE_COLLECTION_CLASS(ReadableByteStreamController
)
47 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ReadableByteStreamController
,
48 ReadableStreamController
)
49 NS_IMPL_CYCLE_COLLECTION_UNLINK(mByobRequest
)
50 tmp
->ClearPendingPullIntos();
52 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
53 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
55 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ReadableByteStreamController
,
56 ReadableStreamController
)
57 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mByobRequest
)
58 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
60 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(ReadableByteStreamController
,
61 ReadableStreamController
)
62 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
63 // Trace the associated queue + list
64 for (const auto& queueEntry
: tmp
->mQueue
) {
65 aCallbacks
.Trace(&queueEntry
->mBuffer
, "mQueue.mBuffer", aClosure
);
67 for (const auto& pullInto
: tmp
->mPendingPullIntos
) {
68 aCallbacks
.Trace(&pullInto
->mBuffer
, "mPendingPullIntos.mBuffer", aClosure
);
70 NS_IMPL_CYCLE_COLLECTION_TRACE_END
72 NS_IMPL_ADDREF_INHERITED(ReadableByteStreamController
, ReadableStreamController
)
73 NS_IMPL_RELEASE_INHERITED(ReadableByteStreamController
,
74 ReadableStreamController
)
75 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ReadableByteStreamController
)
76 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
77 NS_INTERFACE_MAP_END_INHERITING(ReadableStreamController
)
79 ReadableByteStreamController::ReadableByteStreamController(
80 nsIGlobalObject
* aGlobal
)
81 : ReadableStreamController(aGlobal
) {
82 mozilla::HoldJSObjects(this);
85 ReadableByteStreamController::~ReadableByteStreamController() {
86 ClearPendingPullIntos();
88 mozilla::DropJSObjects(this);
91 void ReadableByteStreamController::ClearQueue() {
92 // Since the pull intos are traced only by the owning
93 // ReadableByteStreamController, when clearning the list we also clear JS
94 // references to avoid dangling JS references.
95 for (auto* queueEntry
: mQueue
) {
96 queueEntry
->ClearBuffer();
101 void ReadableByteStreamController::ClearPendingPullIntos() {
102 // Since the pull intos are traced only by the owning
103 // ReadableByteStreamController, when clearning the list we also clear JS
104 // references to avoid dangling JS references.
105 for (auto* pullInto
: mPendingPullIntos
) {
106 pullInto
->ClearBuffer();
108 mPendingPullIntos
.clear();
111 namespace streams_abstract
{
112 // https://streams.spec.whatwg.org/#abstract-opdef-readablebytestreamcontrollergetbyobrequest
113 already_AddRefed
<ReadableStreamBYOBRequest
>
114 ReadableByteStreamControllerGetBYOBRequest(
115 JSContext
* aCx
, ReadableByteStreamController
* aController
,
118 if (!aController
->GetByobRequest() &&
119 !aController
->PendingPullIntos().isEmpty()) {
121 PullIntoDescriptor
* firstDescriptor
=
122 aController
->PendingPullIntos().getFirst();
125 aRv
.MightThrowJSException();
126 JS::Rooted
<JSObject
*> buffer(aCx
, firstDescriptor
->Buffer());
127 JS::Rooted
<JSObject
*> view(
128 aCx
, JS_NewUint8ArrayWithBuffer(
130 firstDescriptor
->ByteOffset() + firstDescriptor
->BytesFilled(),
131 int64_t(firstDescriptor
->ByteLength() -
132 firstDescriptor
->BytesFilled())));
134 aRv
.StealExceptionFromJSContext(aCx
);
139 RefPtr
<ReadableStreamBYOBRequest
> byobRequest
=
140 new ReadableStreamBYOBRequest(aController
->GetParentObject());
143 byobRequest
->SetController(aController
);
146 byobRequest
->SetView(view
);
149 aController
->SetByobRequest(byobRequest
);
153 RefPtr
<ReadableStreamBYOBRequest
> request(aController
->GetByobRequest());
154 return request
.forget();
156 } // namespace streams_abstract
158 already_AddRefed
<ReadableStreamBYOBRequest
>
159 ReadableByteStreamController::GetByobRequest(JSContext
* aCx
, ErrorResult
& aRv
) {
160 return ReadableByteStreamControllerGetBYOBRequest(aCx
, this, aRv
);
163 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-get-desired-size
164 Nullable
<double> ReadableByteStreamControllerGetDesiredSize(
165 const ReadableByteStreamController
* aController
) {
167 ReadableStream::ReaderState state
= aController
->Stream()->State();
170 if (state
== ReadableStream::ReaderState::Errored
) {
175 if (state
== ReadableStream::ReaderState::Closed
) {
180 return aController
->StrategyHWM() - aController
->QueueTotalSize();
183 Nullable
<double> ReadableByteStreamController::GetDesiredSize() const {
185 return ReadableByteStreamControllerGetDesiredSize(this);
188 JSObject
* ReadableByteStreamController::WrapObject(
189 JSContext
* aCx
, JS::Handle
<JSObject
*> aGivenProto
) {
190 return ReadableByteStreamController_Binding::Wrap(aCx
, this, aGivenProto
);
193 namespace streams_abstract
{
195 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-invalidate-byob-request
196 static void ReadableByteStreamControllerInvalidateBYOBRequest(
197 ReadableByteStreamController
* aController
) {
199 if (!aController
->GetByobRequest()) {
204 aController
->GetByobRequest()->SetController(nullptr);
207 aController
->GetByobRequest()->SetView(nullptr);
210 aController
->SetByobRequest(nullptr);
213 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-clear-pending-pull-intos
214 void ReadableByteStreamControllerClearPendingPullIntos(
215 ReadableByteStreamController
* aController
) {
217 ReadableByteStreamControllerInvalidateBYOBRequest(aController
);
220 aController
->ClearPendingPullIntos();
223 // https://streams.spec.whatwg.org/#reset-queue
224 void ResetQueue(ReadableByteStreamController
* aContainer
) {
225 // Step 1. Implied by type.
227 aContainer
->ClearQueue();
230 aContainer
->SetQueueTotalSize(0);
233 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-clear-algorithms
234 void ReadableByteStreamControllerClearAlgorithms(
235 ReadableByteStreamController
* aController
) {
236 // Step 1. Set controller.[[pullAlgorithm]] to undefined.
237 // Step 2. Set controller.[[cancelAlgorithm]] to undefined.
238 aController
->ClearAlgorithms();
241 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-error
242 void ReadableByteStreamControllerError(
243 ReadableByteStreamController
* aController
, JS::Handle
<JS::Value
> aValue
,
245 // Step 1. Let stream be controller.[[stream]].
246 ReadableStream
* stream
= aController
->Stream();
248 // Step 2. If stream.[[state]] is not "readable", return.
249 if (stream
->State() != ReadableStream::ReaderState::Readable
) {
254 // !ReadableByteStreamControllerClearPendingPullIntos(controller).
255 ReadableByteStreamControllerClearPendingPullIntos(aController
);
257 // Step 4. Perform !ResetQueue(controller).
258 ResetQueue(aController
);
260 // Step 5. Perform !ReadableByteStreamControllerClearAlgorithms(controller).
261 ReadableByteStreamControllerClearAlgorithms(aController
);
263 // Step 6. Perform !ReadableStreamError(stream, e).
265 if (!jsapi
.Init(aController
->GetParentObject())) {
268 ReadableStreamError(jsapi
.cx(), stream
, aValue
, aRv
);
271 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-close
272 void ReadableByteStreamControllerClose(
273 JSContext
* aCx
, ReadableByteStreamController
* aController
,
276 RefPtr
<ReadableStream
> stream
= aController
->Stream();
279 if (aController
->CloseRequested() ||
280 stream
->State() != ReadableStream::ReaderState::Readable
) {
285 if (aController
->QueueTotalSize() > 0) {
287 aController
->SetCloseRequested(true);
293 if (!aController
->PendingPullIntos().isEmpty()) {
295 PullIntoDescriptor
* firstPendingPullInto
=
296 aController
->PendingPullIntos().getFirst();
298 if (firstPendingPullInto
->BytesFilled() > 0) {
301 rv
.ThrowTypeError("Leftover Bytes");
303 JS::Rooted
<JS::Value
> exception(aCx
);
304 MOZ_ALWAYS_TRUE(ToJSValue(aCx
, std::move(rv
), &exception
));
307 ReadableByteStreamControllerError(aController
, exception
, aRv
);
312 aRv
.MightThrowJSException();
313 aRv
.ThrowJSException(aCx
, exception
);
319 ReadableByteStreamControllerClearAlgorithms(aController
);
322 ReadableStreamClose(aCx
, stream
, aRv
);
325 } // namespace streams_abstract
327 // https://streams.spec.whatwg.org/#rbs-controller-close
328 void ReadableByteStreamController::Close(JSContext
* aCx
, ErrorResult
& aRv
) {
330 if (mCloseRequested
) {
331 aRv
.ThrowTypeError("Close already requested");
336 if (Stream()->State() != ReadableStream::ReaderState::Readable
) {
337 aRv
.ThrowTypeError("Closing un-readable stream controller");
342 ReadableByteStreamControllerClose(aCx
, this, aRv
);
345 namespace streams_abstract
{
347 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-enqueue-chunk-to-queue
348 void ReadableByteStreamControllerEnqueueChunkToQueue(
349 ReadableByteStreamController
* aController
,
350 JS::Handle
<JSObject
*> aTransferredBuffer
, size_t aByteOffset
,
351 size_t aByteLength
) {
353 RefPtr
<ReadableByteStreamQueueEntry
> queueEntry
=
354 new ReadableByteStreamQueueEntry(aTransferredBuffer
, aByteOffset
,
356 aController
->Queue().insertBack(queueEntry
);
359 aController
->AddToQueueTotalSize(double(aByteLength
));
362 // https://streams.spec.whatwg.org/#abstract-opdef-readablebytestreamcontrollerenqueueclonedchunktoqueue
363 void ReadableByteStreamControllerEnqueueClonedChunkToQueue(
364 JSContext
* aCx
, ReadableByteStreamController
* aController
,
365 JS::Handle
<JSObject
*> aBuffer
, size_t aByteOffset
, size_t aByteLength
,
367 // Step 1. Let cloneResult be CloneArrayBuffer(buffer, byteOffset, byteLength,
369 aRv
.MightThrowJSException();
370 JS::Rooted
<JSObject
*> cloneResult(
371 aCx
, JS::ArrayBufferClone(aCx
, aBuffer
, aByteOffset
, aByteLength
));
373 // Step 2. If cloneResult is an abrupt completion,
375 JS::Rooted
<JS::Value
> exception(aCx
);
376 if (!JS_GetPendingException(aCx
, &exception
)) {
377 // Uncatchable exception; we should mark aRv and return.
378 aRv
.StealExceptionFromJSContext(aCx
);
381 JS_ClearPendingException(aCx
);
383 // Step 2.1. Perform ! ReadableByteStreamControllerError(controller,
384 // cloneResult.[[Value]]).
385 ReadableByteStreamControllerError(aController
, exception
, aRv
);
390 // Step 2.2. Return cloneResult.
391 aRv
.ThrowJSException(aCx
, exception
);
396 // ReadableByteStreamControllerEnqueueChunkToQueue(controller,
397 // cloneResult.[[Value]], 0, byteLength).
398 ReadableByteStreamControllerEnqueueChunkToQueue(aController
, cloneResult
, 0,
402 already_AddRefed
<PullIntoDescriptor
>
403 ReadableByteStreamControllerShiftPendingPullInto(
404 ReadableByteStreamController
* aController
);
406 // https://streams.spec.whatwg.org/#abstract-opdef-readablebytestreamcontrollerenqueuedetachedpullintotoqueue
407 void ReadableByteStreamControllerEnqueueDetachedPullIntoToQueue(
408 JSContext
* aCx
, ReadableByteStreamController
* aController
,
409 PullIntoDescriptor
* aPullIntoDescriptor
, ErrorResult
& aRv
) {
410 // Step 1. Assert: pullIntoDescriptor’s reader type is "none".
411 MOZ_ASSERT(aPullIntoDescriptor
->GetReaderType() == ReaderType::None
);
413 // Step 2. If pullIntoDescriptor’s bytes filled > 0,
414 // perform ? ReadableByteStreamControllerEnqueueClonedChunkToQueue(controller,
415 // pullIntoDescriptor’s buffer, pullIntoDescriptor’s byte offset,
416 // pullIntoDescriptor’s bytes filled).
417 if (aPullIntoDescriptor
->BytesFilled() > 0) {
418 JS::Rooted
<JSObject
*> buffer(aCx
, aPullIntoDescriptor
->Buffer());
419 ReadableByteStreamControllerEnqueueClonedChunkToQueue(
420 aCx
, aController
, buffer
, aPullIntoDescriptor
->ByteOffset(),
421 aPullIntoDescriptor
->BytesFilled(), aRv
);
428 // ReadableByteStreamControllerShiftPendingPullInto(controller).
429 RefPtr
<PullIntoDescriptor
> discarded
=
430 ReadableByteStreamControllerShiftPendingPullInto(aController
);
434 // https://streams.spec.whatwg.org/#readable-stream-get-num-read-into-requests
435 static size_t ReadableStreamGetNumReadIntoRequests(ReadableStream
* aStream
) {
437 MOZ_ASSERT(ReadableStreamHasBYOBReader(aStream
));
440 return aStream
->GetReader()->AsBYOB()->ReadIntoRequests().length();
443 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-should-call-pull
444 bool ReadableByteStreamControllerShouldCallPull(
445 ReadableByteStreamController
* aController
) {
446 // Step 1. Let stream be controller.[[stream]].
447 ReadableStream
* stream
= aController
->Stream();
449 // Step 2. If stream.[[state]] is not "readable", return false.
450 if (stream
->State() != ReadableStream::ReaderState::Readable
) {
454 // Step 3. If controller.[[closeRequested]] is true, return false.
455 if (aController
->CloseRequested()) {
459 // Step 4. If controller.[[started]] is false, return false.
460 if (!aController
->Started()) {
464 // Step 5. If ! ReadableStreamHasDefaultReader(stream) is true
465 // and ! ReadableStreamGetNumReadRequests(stream) > 0, return true.
466 if (ReadableStreamHasDefaultReader(stream
) &&
467 ReadableStreamGetNumReadRequests(stream
) > 0) {
471 // Step 6. If ! ReadableStreamHasBYOBReader(stream) is true
472 // and ! ReadableStreamGetNumReadIntoRequests(stream) > 0, return true.
473 if (ReadableStreamHasBYOBReader(stream
) &&
474 ReadableStreamGetNumReadIntoRequests(stream
) > 0) {
478 // Step 7. Let desiredSize be
479 // ! ReadableByteStreamControllerGetDesiredSize(controller).
480 Nullable
<double> desiredSize
=
481 ReadableByteStreamControllerGetDesiredSize(aController
);
483 // Step 8. Assert: desiredSize is not null.
484 MOZ_ASSERT(!desiredSize
.IsNull());
486 // Step 9. If desiredSize > 0, return true.
487 // Step 10. Return false.
488 return desiredSize
.Value() > 0;
491 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-call-pull-if-needed
492 void ReadableByteStreamControllerCallPullIfNeeded(
493 JSContext
* aCx
, ReadableByteStreamController
* aController
,
496 bool shouldPull
= ReadableByteStreamControllerShouldCallPull(aController
);
504 if (aController
->Pulling()) {
505 aController
->SetPullAgain(true);
510 MOZ_ASSERT(!aController
->PullAgain());
513 aController
->SetPulling(true);
516 RefPtr
<ReadableStreamController
> controller(aController
);
517 RefPtr
<UnderlyingSourceAlgorithmsBase
> algorithms
=
518 aController
->GetAlgorithms();
519 RefPtr
<Promise
> pullPromise
= algorithms
->PullCallback(aCx
, *controller
, aRv
);
525 pullPromise
->AddCallbacksWithCycleCollectedArgs(
526 [](JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
, ErrorResult
& aRv
,
527 ReadableByteStreamController
* aController
)
528 MOZ_CAN_RUN_SCRIPT_BOUNDARY
{
530 aController
->SetPulling(false);
532 if (aController
->PullAgain()) {
534 aController
->SetPullAgain(false);
537 ReadableByteStreamControllerCallPullIfNeeded(
538 aCx
, MOZ_KnownLive(aController
), aRv
);
541 [](JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
, ErrorResult
& aRv
,
542 ReadableByteStreamController
* aController
) {
544 ReadableByteStreamControllerError(aController
, aValue
, aRv
);
546 RefPtr(aController
));
549 bool ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(
550 JSContext
* aCx
, ReadableByteStreamController
* aController
,
551 PullIntoDescriptor
* aPullIntoDescriptor
, ErrorResult
& aRv
);
553 JSObject
* ReadableByteStreamControllerConvertPullIntoDescriptor(
554 JSContext
* aCx
, PullIntoDescriptor
* pullIntoDescriptor
, ErrorResult
& aRv
);
556 // https://streams.spec.whatwg.org/#readable-stream-fulfill-read-into-request
558 void ReadableStreamFulfillReadIntoRequest(JSContext
* aCx
,
559 ReadableStream
* aStream
,
560 JS::Handle
<JS::Value
> aChunk
,
561 bool done
, ErrorResult
& aRv
) {
562 // Step 1. Assert: !ReadableStreamHasBYOBReader(stream) is true.
563 MOZ_ASSERT(ReadableStreamHasBYOBReader(aStream
));
565 // Step 2. Let reader be stream.[[reader]].
566 ReadableStreamBYOBReader
* reader
= aStream
->GetReader()->AsBYOB();
568 // Step 3. Assert: reader.[[readIntoRequests]] is not empty.
569 MOZ_ASSERT(!reader
->ReadIntoRequests().isEmpty());
571 // Step 4. Let readIntoRequest be reader.[[readIntoRequests]][0].
572 // Step 5. Remove readIntoRequest from reader.[[readIntoRequests]].
573 RefPtr
<ReadIntoRequest
> readIntoRequest
=
574 reader
->ReadIntoRequests().popFirst();
576 // Step 6. If done is true, perform readIntoRequest’s close steps, given
579 readIntoRequest
->CloseSteps(aCx
, aChunk
, aRv
);
583 // Step 7. Otherwise, perform readIntoRequest’s chunk steps, given chunk.
584 readIntoRequest
->ChunkSteps(aCx
, aChunk
, aRv
);
587 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-commit-pull-into-descriptor
589 void ReadableByteStreamControllerCommitPullIntoDescriptor(
590 JSContext
* aCx
, ReadableStream
* aStream
,
591 PullIntoDescriptor
* pullIntoDescriptor
, ErrorResult
& aRv
) {
592 // Step 1. Assert: stream.[[state]] is not "errored".
593 MOZ_ASSERT(aStream
->State() != ReadableStream::ReaderState::Errored
);
595 // Step 2. Assert: pullIntoDescriptor.reader type is not "none".
596 MOZ_ASSERT(pullIntoDescriptor
->GetReaderType() != ReaderType::None
);
598 // Step 3. Let done be false.
601 // Step 4. If stream.[[state]] is "closed",
602 if (aStream
->State() == ReadableStream::ReaderState::Closed
) {
603 // Step 4.1. Assert: pullIntoDescriptor’s bytes filled is 0.
604 MOZ_ASSERT(pullIntoDescriptor
->BytesFilled() == 0);
606 // Step 4.2. Set done to true.
610 // Step 5. Let filledView be !
611 // ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor).
612 JS::Rooted
<JSObject
*> filledView(
613 aCx
, ReadableByteStreamControllerConvertPullIntoDescriptor(
614 aCx
, pullIntoDescriptor
, aRv
));
618 JS::Rooted
<JS::Value
> filledViewValue(aCx
, JS::ObjectValue(*filledView
));
620 // Step 6. If pullIntoDescriptor’s reader type is "default",
621 if (pullIntoDescriptor
->GetReaderType() == ReaderType::Default
) {
622 // Step 6.1. Perform !ReadableStreamFulfillReadRequest(stream, filledView,
624 ReadableStreamFulfillReadRequest(aCx
, aStream
, filledViewValue
, done
, aRv
);
628 // Step 7.1. Assert: pullIntoDescriptor’s reader type is "byob".
629 MOZ_ASSERT(pullIntoDescriptor
->GetReaderType() == ReaderType::BYOB
);
631 // Step 7.2 Perform !ReadableStreamFulfillReadIntoRequest(stream, filledView,
633 ReadableStreamFulfillReadIntoRequest(aCx
, aStream
, filledViewValue
, done
,
637 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-process-pull-into-descriptors-using-queue
639 void ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(
640 JSContext
* aCx
, ReadableByteStreamController
* aController
,
642 // Step 1. Assert: controller.[[closeRequested]] is false.
643 MOZ_ASSERT(!aController
->CloseRequested());
645 // Step 2. While controller.[[pendingPullIntos]] is not empty,
646 while (!aController
->PendingPullIntos().isEmpty()) {
647 // Step 2.1 If controller.[[queueTotalSize]] is 0, return.
648 if (aController
->QueueTotalSize() == 0) {
652 // Step 2.2. Let pullIntoDescriptor be controller.[[pendingPullIntos]][0].
653 RefPtr
<PullIntoDescriptor
> pullIntoDescriptor
=
654 aController
->PendingPullIntos().getFirst();
657 // !ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller,
658 // pullIntoDescriptor) is true,
659 bool ready
= ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(
660 aCx
, aController
, pullIntoDescriptor
, aRv
);
666 // Step 2.3.1. Perform
667 // !ReadableByteStreamControllerShiftPendingPullInto(controller).
668 RefPtr
<PullIntoDescriptor
> discardedPullIntoDescriptor
=
669 ReadableByteStreamControllerShiftPendingPullInto(aController
);
671 // Step 2.3.2. Perform
672 // !ReadableByteStreamControllerCommitPullIntoDescriptor(controller.[[stream]],
673 // pullIntoDescriptor).
674 RefPtr
<ReadableStream
> stream(aController
->Stream());
675 ReadableByteStreamControllerCommitPullIntoDescriptor(
676 aCx
, stream
, pullIntoDescriptor
, aRv
);
685 void ReadableByteStreamControllerHandleQueueDrain(
686 JSContext
* aCx
, ReadableByteStreamController
* aController
,
689 // https://streams.spec.whatwg.org/#abstract-opdef-readablebytestreamcontrollerfillreadrequestfromqueue
690 MOZ_CAN_RUN_SCRIPT
void ReadableByteStreamControllerFillReadRequestFromQueue(
691 JSContext
* aCx
, ReadableByteStreamController
* aController
,
692 ReadRequest
* aReadRequest
, ErrorResult
& aRv
) {
693 // Step 1. Assert: controller.[[queueTotalSize]] > 0.
694 MOZ_ASSERT(aController
->QueueTotalSize() > 0);
695 // Also assert that the queue has a non-zero length;
696 MOZ_ASSERT(aController
->Queue().length() > 0);
698 // Step 2. Let entry be controller.[[queue]][0].
699 // Step 3. Remove entry from controller.[[queue]].
700 RefPtr
<ReadableByteStreamQueueEntry
> entry
= aController
->Queue().popFirst();
702 // Assert that we actually got an entry.
705 // Step 4. Set controller.[[queueTotalSize]] to controller.[[queueTotalSize]]
706 // − entry’s byte length.
707 aController
->SetQueueTotalSize(aController
->QueueTotalSize() -
708 double(entry
->ByteLength()));
710 // Step 5. Perform ! ReadableByteStreamControllerHandleQueueDrain(controller).
711 ReadableByteStreamControllerHandleQueueDrain(aCx
, aController
, aRv
);
716 // Step 6. Let view be ! Construct(%Uint8Array%, « entry’s buffer, entry’s
717 // byte offset, entry’s byte length »).
718 aRv
.MightThrowJSException();
719 JS::Rooted
<JSObject
*> buffer(aCx
, entry
->Buffer());
720 JS::Rooted
<JSObject
*> view(
721 aCx
, JS_NewUint8ArrayWithBuffer(aCx
, buffer
, entry
->ByteOffset(),
722 int64_t(entry
->ByteLength())));
724 aRv
.StealExceptionFromJSContext(aCx
);
728 // Step 7. Perform readRequest’s chunk steps, given view.
729 JS::Rooted
<JS::Value
> viewValue(aCx
, JS::ObjectValue(*view
));
730 aReadRequest
->ChunkSteps(aCx
, viewValue
, aRv
);
733 MOZ_CAN_RUN_SCRIPT
void
734 ReadableByteStreamControllerProcessReadRequestsUsingQueue(
735 JSContext
* aCx
, ReadableByteStreamController
* aController
,
737 // Step 1. Let reader be controller.[[stream]].[[reader]].
738 // Step 2. Assert: reader implements ReadableStreamDefaultReader.
739 RefPtr
<ReadableStreamDefaultReader
> reader
=
740 aController
->Stream()->GetDefaultReader();
742 // Step 3. While reader.[[readRequests]] is not empty,
743 while (!reader
->ReadRequests().isEmpty()) {
744 // Step 3.1. If controller.[[queueTotalSize]] is 0, return.
745 if (aController
->QueueTotalSize() == 0) {
749 // Step 3.2. Let readRequest be reader.[[readRequests]][0].
750 // Step 3.3. Remove readRequest from reader.[[readRequests]].
751 RefPtr
<ReadRequest
> readRequest
= reader
->ReadRequests().popFirst();
753 // Step 3.4. Perform !
754 // ReadableByteStreamControllerFillReadRequestFromQueue(controller,
756 ReadableByteStreamControllerFillReadRequestFromQueue(aCx
, aController
,
764 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-enqueue
765 void ReadableByteStreamControllerEnqueue(
766 JSContext
* aCx
, ReadableByteStreamController
* aController
,
767 JS::Handle
<JSObject
*> aChunk
, ErrorResult
& aRv
) {
768 aRv
.MightThrowJSException();
771 RefPtr
<ReadableStream
> stream
= aController
->Stream();
774 if (aController
->CloseRequested() ||
775 stream
->State() != ReadableStream::ReaderState::Readable
) {
781 JS::Rooted
<JSObject
*> buffer(
782 aCx
, JS_GetArrayBufferViewBuffer(aCx
, aChunk
, &isShared
));
784 aRv
.StealExceptionFromJSContext(aCx
);
789 size_t byteOffset
= JS_GetArrayBufferViewByteOffset(aChunk
);
792 size_t byteLength
= JS_GetArrayBufferViewByteLength(aChunk
);
795 if (JS::IsDetachedArrayBufferObject(buffer
)) {
796 aRv
.ThrowTypeError("Detatched Array Buffer");
801 JS::Rooted
<JSObject
*> transferredBuffer(aCx
,
802 TransferArrayBuffer(aCx
, buffer
));
803 if (!transferredBuffer
) {
804 aRv
.StealExceptionFromJSContext(aCx
);
809 if (!aController
->PendingPullIntos().isEmpty()) {
811 RefPtr
<PullIntoDescriptor
> firstPendingPullInto
=
812 aController
->PendingPullIntos().getFirst();
815 JS::Rooted
<JSObject
*> pendingBuffer(aCx
, firstPendingPullInto
->Buffer());
816 if (JS::IsDetachedArrayBufferObject(pendingBuffer
)) {
817 aRv
.ThrowTypeError("Pending PullInto has detached buffer");
821 // Step 8.3. Perform !
822 // ReadableByteStreamControllerInvalidateBYOBRequest(controller).
823 ReadableByteStreamControllerInvalidateBYOBRequest(aController
);
825 // Step 8.4. Set firstPendingPullInto’s buffer to !
826 // TransferArrayBuffer(firstPendingPullInto’s buffer).
827 pendingBuffer
= TransferArrayBuffer(aCx
, pendingBuffer
);
828 if (!pendingBuffer
) {
829 aRv
.StealExceptionFromJSContext(aCx
);
832 firstPendingPullInto
->SetBuffer(pendingBuffer
);
834 // Step 8.5. If firstPendingPullInto’s reader type is "none", perform ?
835 // ReadableByteStreamControllerEnqueueDetachedPullIntoToQueue(controller,
836 // firstPendingPullInto).
837 if (firstPendingPullInto
->GetReaderType() == ReaderType::None
) {
838 ReadableByteStreamControllerEnqueueDetachedPullIntoToQueue(
839 aCx
, aController
, firstPendingPullInto
, aRv
);
846 // Step 9. If ! ReadableStreamHasDefaultReader(stream) is true,
847 if (ReadableStreamHasDefaultReader(stream
)) {
848 // Step 9.1. Perform !
849 // ReadableByteStreamControllerProcessReadRequestsUsingQueue(controller).
850 ReadableByteStreamControllerProcessReadRequestsUsingQueue(aCx
, aController
,
856 // Step 9.2. If ! ReadableStreamGetNumReadRequests(stream) is 0,
857 if (ReadableStreamGetNumReadRequests(stream
) == 0) {
858 // Step 9.2.1 Assert: controller.[[pendingPullIntos]] is empty.
859 MOZ_ASSERT(aController
->PendingPullIntos().isEmpty());
861 // Step 9.2.2. Perform !
862 // ReadableByteStreamControllerEnqueueChunkToQueue(controller,
863 // transferredBuffer, byteOffset, byteLength).
864 ReadableByteStreamControllerEnqueueChunkToQueue(
865 aController
, transferredBuffer
, byteOffset
, byteLength
);
867 // Step 9.3. Otherwise,
869 // Step 9.3.1 Assert: controller.[[queue]] is empty.
870 MOZ_ASSERT(aController
->Queue().isEmpty());
872 // Step 9.3.2. If controller.[[pendingPullIntos]] is not empty,
873 if (!aController
->PendingPullIntos().isEmpty()) {
874 // Step 9.3.2.1. Assert: controller.[[pendingPullIntos]][0]'s reader
875 // type is "default".
877 aController
->PendingPullIntos().getFirst()->GetReaderType() ==
878 ReaderType::Default
);
880 // Step 9.3.2.2. Perform !
881 // ReadableByteStreamControllerShiftPendingPullInto(controller).
882 RefPtr
<PullIntoDescriptor
> pullIntoDescriptor
=
883 ReadableByteStreamControllerShiftPendingPullInto(aController
);
884 (void)pullIntoDescriptor
;
887 // Step 9.3.3. Let transferredView be ! Construct(%Uint8Array%, «
888 // transferredBuffer, byteOffset, byteLength »).
889 JS::Rooted
<JSObject
*> transferredView(
890 aCx
, JS_NewUint8ArrayWithBuffer(aCx
, transferredBuffer
, byteOffset
,
891 int64_t(byteLength
)));
892 if (!transferredView
) {
893 aRv
.StealExceptionFromJSContext(aCx
);
897 // Step 9.3.4. Perform ! ReadableStreamFulfillReadRequest(stream,
898 // transferredView, false).
899 JS::Rooted
<JS::Value
> transferredViewValue(
900 aCx
, JS::ObjectValue(*transferredView
));
901 ReadableStreamFulfillReadRequest(aCx
, stream
, transferredViewValue
, false,
908 // Step 10. Otherwise, if ! ReadableStreamHasBYOBReader(stream) is true,
909 } else if (ReadableStreamHasBYOBReader(stream
)) {
910 // Step 10.1. Perform !
911 // ReadableByteStreamControllerEnqueueChunkToQueue(controller,
912 // transferredBuffer, byteOffset, byteLength).
913 ReadableByteStreamControllerEnqueueChunkToQueue(
914 aController
, transferredBuffer
, byteOffset
, byteLength
);
916 // Step 10.2 Perform !
917 // ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller).
918 ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(
919 aCx
, aController
, aRv
);
924 // Step 11. Otherwise,
926 // Step 11.1. Assert: ! IsReadableStreamLocked(stream) is false.
927 MOZ_ASSERT(!IsReadableStreamLocked(stream
));
929 // Step 11.2. Perform !
930 // ReadableByteStreamControllerEnqueueChunkToQueue(controller,
931 // transferredBuffer, byteOffset, byteLength).
932 ReadableByteStreamControllerEnqueueChunkToQueue(
933 aController
, transferredBuffer
, byteOffset
, byteLength
);
936 // Step 12. Perform !
937 // ReadableByteStreamControllerCallPullIfNeeded(controller).
938 ReadableByteStreamControllerCallPullIfNeeded(aCx
, aController
, aRv
);
941 } // namespace streams_abstract
943 // https://streams.spec.whatwg.org/#rbs-controller-enqueue
944 void ReadableByteStreamController::Enqueue(JSContext
* aCx
,
945 const ArrayBufferView
& aChunk
,
948 JS::Rooted
<JSObject
*> chunk(aCx
, aChunk
.Obj());
949 if (JS_GetArrayBufferViewByteLength(chunk
) == 0) {
950 aRv
.ThrowTypeError("Zero Length View");
956 JS::Rooted
<JSObject
*> viewedArrayBuffer(
957 aCx
, JS_GetArrayBufferViewBuffer(aCx
, chunk
, &isShared
));
958 if (!viewedArrayBuffer
) {
959 aRv
.StealExceptionFromJSContext(aCx
);
963 if (JS::GetArrayBufferByteLength(viewedArrayBuffer
) == 0) {
964 aRv
.ThrowTypeError("Zero Length Buffer");
969 if (CloseRequested()) {
970 aRv
.ThrowTypeError("close requested");
975 if (Stream()->State() != ReadableStream::ReaderState::Readable
) {
976 aRv
.ThrowTypeError("Not Readable");
981 ReadableByteStreamControllerEnqueue(aCx
, this, chunk
, aRv
);
984 // https://streams.spec.whatwg.org/#rbs-controller-error
985 void ReadableByteStreamController::Error(JSContext
* aCx
,
986 JS::Handle
<JS::Value
> aErrorValue
,
989 ReadableByteStreamControllerError(this, aErrorValue
, aRv
);
992 // https://streams.spec.whatwg.org/#rbs-controller-private-cancel
993 already_AddRefed
<Promise
> ReadableByteStreamController::CancelSteps(
994 JSContext
* aCx
, JS::Handle
<JS::Value
> aReason
, ErrorResult
& aRv
) {
996 ReadableByteStreamControllerClearPendingPullIntos(this);
1002 Optional
<JS::Handle
<JS::Value
>> reason(aCx
, aReason
);
1003 RefPtr
<UnderlyingSourceAlgorithmsBase
> algorithms
= mAlgorithms
;
1004 RefPtr
<Promise
> result
= algorithms
->CancelCallback(aCx
, reason
, aRv
);
1005 if (NS_WARN_IF(aRv
.Failed())) {
1009 ReadableByteStreamControllerClearAlgorithms(this);
1012 return result
.forget();
1015 namespace streams_abstract
{
1016 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-handle-queue-drain
1017 void ReadableByteStreamControllerHandleQueueDrain(
1018 JSContext
* aCx
, ReadableByteStreamController
* aController
,
1021 MOZ_ASSERT(aController
->Stream()->State() ==
1022 ReadableStream::ReaderState::Readable
);
1025 if (aController
->QueueTotalSize() == 0 && aController
->CloseRequested()) {
1027 ReadableByteStreamControllerClearAlgorithms(aController
);
1030 RefPtr
<ReadableStream
> stream
= aController
->Stream();
1031 ReadableStreamClose(aCx
, stream
, aRv
);
1036 ReadableByteStreamControllerCallPullIfNeeded(aCx
, aController
, aRv
);
1038 } // namespace streams_abstract
1040 // https://streams.spec.whatwg.org/#rbs-controller-private-pull
1041 void ReadableByteStreamController::PullSteps(JSContext
* aCx
,
1042 ReadRequest
* aReadRequest
,
1045 ReadableStream
* stream
= Stream();
1048 MOZ_ASSERT(ReadableStreamHasDefaultReader(stream
));
1051 if (QueueTotalSize() > 0) {
1052 // Step 3.1. Assert: ! ReadableStreamGetNumReadRequests ( stream ) is 0.
1053 MOZ_ASSERT(ReadableStreamGetNumReadRequests(stream
) == 0);
1055 // Step 3.2. Perform !
1056 // ReadableByteStreamControllerFillReadRequestFromQueue(this, readRequest).
1057 ReadableByteStreamControllerFillReadRequestFromQueue(aCx
, this,
1060 // Step 3.3. Return.
1065 Maybe
<uint64_t> autoAllocateChunkSize
= AutoAllocateChunkSize();
1068 if (autoAllocateChunkSize
) {
1070 aRv
.MightThrowJSException();
1071 JS::Rooted
<JSObject
*> buffer(
1072 aCx
, JS::NewArrayBuffer(aCx
, *autoAllocateChunkSize
));
1076 JS::Rooted
<JS::Value
> bufferError(aCx
);
1077 if (!JS_GetPendingException(aCx
, &bufferError
)) {
1078 // Uncatchable exception; we should mark aRv and return.
1079 aRv
.StealExceptionFromJSContext(aCx
);
1083 // It's not expliclitly stated, but I assume the intention here is that
1084 // we perform a normal completion here.
1085 JS_ClearPendingException(aCx
);
1087 aReadRequest
->ErrorSteps(aCx
, bufferError
, aRv
);
1094 RefPtr
<PullIntoDescriptor
> pullIntoDescriptor
= new PullIntoDescriptor(
1095 buffer
, *autoAllocateChunkSize
, 0, *autoAllocateChunkSize
, 0, 1,
1096 PullIntoDescriptor::Constructor::Uint8
, ReaderType::Default
);
1099 PendingPullIntos().insertBack(pullIntoDescriptor
);
1103 ReadableStreamAddReadRequest(stream
, aReadRequest
);
1106 ReadableByteStreamControllerCallPullIfNeeded(aCx
, this, aRv
);
1109 // https://streams.spec.whatwg.org/#abstract-opdef-readablebytestreamcontroller-releasesteps
1110 void ReadableByteStreamController::ReleaseSteps() {
1111 // Step 1. If this.[[pendingPullIntos]] is not empty,
1112 if (!PendingPullIntos().isEmpty()) {
1113 // Step 1.1. Let firstPendingPullInto be this.[[pendingPullIntos]][0].
1114 RefPtr
<PullIntoDescriptor
> firstPendingPullInto
=
1115 PendingPullIntos().popFirst();
1117 // Step 1.2. Set firstPendingPullInto’s reader type to "none".
1118 firstPendingPullInto
->SetReaderType(ReaderType::None
);
1120 // Step 1.3. Set this.[[pendingPullIntos]] to the list «
1121 // firstPendingPullInto ».
1122 PendingPullIntos().clear();
1123 PendingPullIntos().insertBack(firstPendingPullInto
);
1127 namespace streams_abstract
{
1129 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-shift-pending-pull-into
1130 already_AddRefed
<PullIntoDescriptor
>
1131 ReadableByteStreamControllerShiftPendingPullInto(
1132 ReadableByteStreamController
* aController
) {
1134 MOZ_ASSERT(!aController
->GetByobRequest());
1137 RefPtr
<PullIntoDescriptor
> descriptor
=
1138 aController
->PendingPullIntos().popFirst();
1141 return descriptor
.forget();
1144 JSObject
* ConstructFromPullIntoConstructor(
1145 JSContext
* aCx
, PullIntoDescriptor::Constructor constructor
,
1146 JS::Handle
<JSObject
*> buffer
, size_t byteOffset
, size_t length
) {
1147 switch (constructor
) {
1148 case PullIntoDescriptor::Constructor::DataView
:
1149 return JS_NewDataView(aCx
, buffer
, byteOffset
, length
);
1152 #define CONSTRUCT_TYPED_ARRAY_TYPE(ExternalT, NativeT, Name) \
1153 case PullIntoDescriptor::Constructor::Name: \
1154 return JS_New##Name##ArrayWithBuffer(aCx, buffer, byteOffset, \
1158 JS_FOR_EACH_TYPED_ARRAY(CONSTRUCT_TYPED_ARRAY_TYPE
)
1160 #undef CONSTRUCT_TYPED_ARRAY_TYPE
1163 MOZ_ASSERT_UNREACHABLE("Unknown PullIntoDescriptor::Constructor");
1168 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-convert-pull-into-descriptor
1169 JSObject
* ReadableByteStreamControllerConvertPullIntoDescriptor(
1170 JSContext
* aCx
, PullIntoDescriptor
* pullIntoDescriptor
, ErrorResult
& aRv
) {
1171 // Step 1. Let bytesFilled be pullIntoDescriptor’s bytes filled.
1172 uint64_t bytesFilled
= pullIntoDescriptor
->BytesFilled();
1174 // Step 2. Let elementSize be pullIntoDescriptor’s element size.
1175 uint64_t elementSize
= pullIntoDescriptor
->ElementSize();
1177 // Step 3. Assert: bytesFilled ≤ pullIntoDescriptor’s byte length.
1178 MOZ_ASSERT(bytesFilled
<= pullIntoDescriptor
->ByteLength());
1180 // Step 4. Assert: bytesFilled mod elementSize is 0.
1181 MOZ_ASSERT(bytesFilled
% elementSize
== 0);
1183 // Step 5. Let buffer be ! TransferArrayBuffer(pullIntoDescriptor’s buffer).
1184 aRv
.MightThrowJSException();
1185 JS::Rooted
<JSObject
*> srcBuffer(aCx
, pullIntoDescriptor
->Buffer());
1186 JS::Rooted
<JSObject
*> buffer(aCx
, TransferArrayBuffer(aCx
, srcBuffer
));
1188 aRv
.StealExceptionFromJSContext(aCx
);
1192 // Step 6. Return ! Construct(pullIntoDescriptor’s view constructor,
1193 // « buffer, pullIntoDescriptor’s byte offset, bytesFilled ÷ elementSize »).
1194 JS::Rooted
<JSObject
*> res(
1195 aCx
, ConstructFromPullIntoConstructor(
1196 aCx
, pullIntoDescriptor
->ViewConstructor(), buffer
,
1197 pullIntoDescriptor
->ByteOffset(), bytesFilled
/ elementSize
));
1199 aRv
.StealExceptionFromJSContext(aCx
);
1205 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-in-closed-state
1207 static void ReadableByteStreamControllerRespondInClosedState(
1208 JSContext
* aCx
, ReadableByteStreamController
* aController
,
1209 RefPtr
<PullIntoDescriptor
>& aFirstDescriptor
, ErrorResult
& aRv
) {
1210 // Step 1. Assert: firstDescriptor ’s bytes filled is 0.
1211 MOZ_ASSERT(aFirstDescriptor
->BytesFilled() == 0);
1213 // Step 2. If firstDescriptor’s reader type is "none",
1214 // perform ! ReadableByteStreamControllerShiftPendingPullInto(controller).
1215 if (aFirstDescriptor
->GetReaderType() == ReaderType::None
) {
1216 RefPtr
<PullIntoDescriptor
> discarded
=
1217 ReadableByteStreamControllerShiftPendingPullInto(aController
);
1221 // Step 3. Let stream be controller.[[stream]].
1222 RefPtr
<ReadableStream
> stream
= aController
->Stream();
1224 // Step 4. If ! ReadableStreamHasBYOBReader(stream) is true,
1225 if (ReadableStreamHasBYOBReader(stream
)) {
1226 // Step 4.1. While ! ReadableStreamGetNumReadIntoRequests(stream) > 0,
1227 while (ReadableStreamGetNumReadIntoRequests(stream
) > 0) {
1228 // Step 4.1.1. Let pullIntoDescriptor be !
1229 // ReadableByteStreamControllerShiftPendingPullInto(controller).
1230 RefPtr
<PullIntoDescriptor
> pullIntoDescriptor
=
1231 ReadableByteStreamControllerShiftPendingPullInto(aController
);
1233 // Step 4.1.2. Perform !
1234 // ReadableByteStreamControllerCommitPullIntoDescriptor(stream,
1235 // pullIntoDescriptor).
1236 ReadableByteStreamControllerCommitPullIntoDescriptor(
1237 aCx
, stream
, pullIntoDescriptor
, aRv
);
1242 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-fill-head-pull-into-descriptor
1243 void ReadableByteStreamControllerFillHeadPullIntoDescriptor(
1244 ReadableByteStreamController
* aController
, size_t aSize
,
1245 PullIntoDescriptor
* aPullIntoDescriptor
) {
1246 // Step 1. Assert: either controller.[[pendingPullIntos]] is empty, or
1247 // controller.[[pendingPullIntos]][0] is pullIntoDescriptor.
1248 MOZ_ASSERT(aController
->PendingPullIntos().isEmpty() ||
1249 aController
->PendingPullIntos().getFirst() == aPullIntoDescriptor
);
1251 // Step 2. Assert: controller.[[byobRequest]] is null.
1252 MOZ_ASSERT(!aController
->GetByobRequest());
1254 // Step 3. Set pullIntoDescriptor’s bytes filled to bytes filled + size.
1255 aPullIntoDescriptor
->SetBytesFilled(aPullIntoDescriptor
->BytesFilled() +
1259 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-in-readable-state
1261 static void ReadableByteStreamControllerRespondInReadableState(
1262 JSContext
* aCx
, ReadableByteStreamController
* aController
,
1263 uint64_t aBytesWritten
, PullIntoDescriptor
* aPullIntoDescriptor
,
1265 // Step 1. Assert: pullIntoDescriptor’s bytes filled + bytesWritten ≤
1266 // pullIntoDescriptor’s byte length.
1267 MOZ_ASSERT(aPullIntoDescriptor
->BytesFilled() + aBytesWritten
<=
1268 aPullIntoDescriptor
->ByteLength());
1271 // !ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller,
1272 // bytesWritten, pullIntoDescriptor).
1273 ReadableByteStreamControllerFillHeadPullIntoDescriptor(
1274 aController
, aBytesWritten
, aPullIntoDescriptor
);
1276 // Step 3. If pullIntoDescriptor’s reader type is "none",
1277 if (aPullIntoDescriptor
->GetReaderType() == ReaderType::None
) {
1278 // Step 3.1. Perform ?
1279 // ReadableByteStreamControllerEnqueueDetachedPullIntoToQueue(controller,
1280 // pullIntoDescriptor).
1281 ReadableByteStreamControllerEnqueueDetachedPullIntoToQueue(
1282 aCx
, aController
, aPullIntoDescriptor
, aRv
);
1287 // Step 3.2. Perform !
1288 // ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller).
1289 ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(
1290 aCx
, aController
, aRv
);
1292 // Step 3.3. Return.
1296 // Step 4. If pullIntoDescriptor’s bytes filled < pullIntoDescriptor’s element
1298 if (aPullIntoDescriptor
->BytesFilled() < aPullIntoDescriptor
->ElementSize()) {
1303 // !ReadableByteStreamControllerShiftPendingPullInto(controller).
1304 RefPtr
<PullIntoDescriptor
> pullIntoDescriptor
=
1305 ReadableByteStreamControllerShiftPendingPullInto(aController
);
1306 (void)pullIntoDescriptor
;
1308 // Step 6. Let remainderSize be pullIntoDescriptor’s bytes filled mod
1309 // pullIntoDescriptor’s element size.
1310 size_t remainderSize
=
1311 aPullIntoDescriptor
->BytesFilled() % aPullIntoDescriptor
->ElementSize();
1313 // Step 7. If remainderSize > 0,
1314 if (remainderSize
> 0) {
1315 // Step 7.1. Let end be pullIntoDescriptor’s byte offset +
1316 // pullIntoDescriptor’s bytes filled.
1318 aPullIntoDescriptor
->ByteOffset() + aPullIntoDescriptor
->BytesFilled();
1320 // Step 7.2. Perform ?
1321 // ReadableByteStreamControllerEnqueueClonedChunkToQueue(controller,
1322 // pullIntoDescriptor’s buffer, end − remainderSize, remainderSize).
1323 JS::Rooted
<JSObject
*> pullIntoBuffer(aCx
, aPullIntoDescriptor
->Buffer());
1324 ReadableByteStreamControllerEnqueueClonedChunkToQueue(
1325 aCx
, aController
, pullIntoBuffer
, end
- remainderSize
, remainderSize
,
1332 // Step 8. Set pullIntoDescriptor’s bytes filled to pullIntoDescriptor’s bytes
1333 // filled − remainderSize.
1334 aPullIntoDescriptor
->SetBytesFilled(aPullIntoDescriptor
->BytesFilled() -
1338 // !ReadableByteStreamControllerCommitPullIntoDescriptor(controller.[[stream]],
1339 // pullIntoDescriptor).
1340 RefPtr
<ReadableStream
> stream(aController
->Stream());
1341 ReadableByteStreamControllerCommitPullIntoDescriptor(
1342 aCx
, stream
, aPullIntoDescriptor
, aRv
);
1348 // !ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller).
1349 ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(
1350 aCx
, aController
, aRv
);
1353 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-internal
1354 void ReadableByteStreamControllerRespondInternal(
1355 JSContext
* aCx
, ReadableByteStreamController
* aController
,
1356 uint64_t aBytesWritten
, ErrorResult
& aRv
) {
1358 RefPtr
<PullIntoDescriptor
> firstDescriptor
=
1359 aController
->PendingPullIntos().getFirst();
1362 JS::Rooted
<JSObject
*> buffer(aCx
, firstDescriptor
->Buffer());
1364 bool canTransferBuffer
= CanTransferArrayBuffer(aCx
, buffer
, aRv
);
1365 MOZ_ASSERT(!aRv
.Failed());
1366 MOZ_ASSERT(canTransferBuffer
);
1370 ReadableByteStreamControllerInvalidateBYOBRequest(aController
);
1373 auto state
= aController
->Stream()->State();
1376 if (state
== ReadableStream::ReaderState::Closed
) {
1378 MOZ_ASSERT(aBytesWritten
== 0);
1381 ReadableByteStreamControllerRespondInClosedState(aCx
, aController
,
1382 firstDescriptor
, aRv
);
1388 MOZ_ASSERT(state
== ReadableStream::ReaderState::Readable
);
1391 MOZ_ASSERT(aBytesWritten
> 0);
1394 ReadableByteStreamControllerRespondInReadableState(
1395 aCx
, aController
, aBytesWritten
, firstDescriptor
, aRv
);
1401 ReadableByteStreamControllerCallPullIfNeeded(aCx
, aController
, aRv
);
1404 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond
1405 void ReadableByteStreamControllerRespond(
1406 JSContext
* aCx
, ReadableByteStreamController
* aController
,
1407 uint64_t aBytesWritten
, ErrorResult
& aRv
) {
1409 MOZ_ASSERT(!aController
->PendingPullIntos().isEmpty());
1412 PullIntoDescriptor
* firstDescriptor
=
1413 aController
->PendingPullIntos().getFirst();
1416 auto state
= aController
->Stream()->State();
1419 if (state
== ReadableStream::ReaderState::Closed
) {
1421 if (aBytesWritten
!= 0) {
1422 aRv
.ThrowTypeError("bytesWritten not zero on closed stream");
1427 MOZ_ASSERT(state
== ReadableStream::ReaderState::Readable
);
1430 if (aBytesWritten
== 0) {
1431 aRv
.ThrowTypeError("bytesWritten 0");
1436 if (firstDescriptor
->BytesFilled() + aBytesWritten
>
1437 firstDescriptor
->ByteLength()) {
1438 aRv
.ThrowRangeError("bytesFilled + bytesWritten > byteLength");
1444 aRv
.MightThrowJSException();
1445 JS::Rooted
<JSObject
*> buffer(aCx
, firstDescriptor
->Buffer());
1446 JS::Rooted
<JSObject
*> transferredBuffer(aCx
,
1447 TransferArrayBuffer(aCx
, buffer
));
1448 if (!transferredBuffer
) {
1449 aRv
.StealExceptionFromJSContext(aCx
);
1452 firstDescriptor
->SetBuffer(transferredBuffer
);
1455 ReadableByteStreamControllerRespondInternal(aCx
, aController
, aBytesWritten
,
1459 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-with-new-view
1460 void ReadableByteStreamControllerRespondWithNewView(
1461 JSContext
* aCx
, ReadableByteStreamController
* aController
,
1462 JS::Handle
<JSObject
*> aView
, ErrorResult
& aRv
) {
1463 aRv
.MightThrowJSException();
1466 MOZ_ASSERT(!aController
->PendingPullIntos().isEmpty());
1469 bool isSharedMemory
;
1470 JS::Rooted
<JSObject
*> viewedArrayBuffer(
1471 aCx
, JS_GetArrayBufferViewBuffer(aCx
, aView
, &isSharedMemory
));
1472 if (!viewedArrayBuffer
) {
1473 aRv
.StealExceptionFromJSContext(aCx
);
1476 MOZ_ASSERT(!JS::IsDetachedArrayBufferObject(viewedArrayBuffer
));
1479 RefPtr
<PullIntoDescriptor
> firstDescriptor
=
1480 aController
->PendingPullIntos().getFirst();
1483 ReadableStream::ReaderState state
= aController
->Stream()->State();
1486 if (state
== ReadableStream::ReaderState::Closed
) {
1488 if (JS_GetArrayBufferViewByteLength(aView
) != 0) {
1489 aRv
.ThrowTypeError("View has non-zero length in closed stream");
1494 MOZ_ASSERT(state
== ReadableStream::ReaderState::Readable
);
1497 if (JS_GetArrayBufferViewByteLength(aView
) == 0) {
1498 aRv
.ThrowTypeError("View has zero length in readable stream");
1504 if (firstDescriptor
->ByteOffset() + firstDescriptor
->BytesFilled() !=
1505 JS_GetArrayBufferViewByteOffset(aView
)) {
1506 aRv
.ThrowRangeError("Invalid Offset");
1511 if (firstDescriptor
->BufferByteLength() !=
1512 JS::GetArrayBufferByteLength(viewedArrayBuffer
)) {
1513 aRv
.ThrowRangeError("Mismatched buffer byte lengths");
1518 if (firstDescriptor
->BytesFilled() + JS_GetArrayBufferViewByteLength(aView
) >
1519 firstDescriptor
->ByteLength()) {
1520 aRv
.ThrowRangeError("Too many bytes");
1524 // Step 10. Let viewByteLength be view.[[ByteLength]].
1525 size_t viewByteLength
= JS_GetArrayBufferViewByteLength(aView
);
1527 // Step 11. Set firstDescriptor’s buffer to ?
1528 // TransferArrayBuffer(view.[[ViewedArrayBuffer]]).
1529 JS::Rooted
<JSObject
*> transferedBuffer(
1530 aCx
, TransferArrayBuffer(aCx
, viewedArrayBuffer
));
1531 if (!transferedBuffer
) {
1532 aRv
.StealExceptionFromJSContext(aCx
);
1535 firstDescriptor
->SetBuffer(transferedBuffer
);
1537 // Step 12. Perform ? ReadableByteStreamControllerRespondInternal(controller,
1539 ReadableByteStreamControllerRespondInternal(aCx
, aController
, viewByteLength
,
1543 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-fill-pull-into-descriptor-from-queue
1544 bool ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(
1545 JSContext
* aCx
, ReadableByteStreamController
* aController
,
1546 PullIntoDescriptor
* aPullIntoDescriptor
, ErrorResult
& aRv
) {
1547 // Step 1. Let elementSize be pullIntoDescriptor.[[elementSize]].
1548 size_t elementSize
= aPullIntoDescriptor
->ElementSize();
1550 // Step 2. Let currentAlignedBytes be pullIntoDescriptor’s bytes filled −
1551 // (pullIntoDescriptor’s bytes filled mod elementSize).
1552 size_t currentAlignedBytes
=
1553 aPullIntoDescriptor
->BytesFilled() -
1554 (aPullIntoDescriptor
->BytesFilled() % elementSize
);
1556 // Step 3. Let maxBytesToCopy be min(controller.[[queueTotalSize]],
1557 // pullIntoDescriptor’s byte length − pullIntoDescriptor’s bytes filled).
1558 size_t maxBytesToCopy
=
1559 std::min(static_cast<size_t>(aController
->QueueTotalSize()),
1560 static_cast<size_t>((aPullIntoDescriptor
->ByteLength() -
1561 aPullIntoDescriptor
->BytesFilled())));
1563 // Step 4. Let maxBytesFilled be pullIntoDescriptor’s bytes filled +
1565 size_t maxBytesFilled
= aPullIntoDescriptor
->BytesFilled() + maxBytesToCopy
;
1567 // Step 5. Let maxAlignedBytes be maxBytesFilled − (maxBytesFilled mod
1569 size_t maxAlignedBytes
= maxBytesFilled
- (maxBytesFilled
% elementSize
);
1571 // Step 6. Let totalBytesToCopyRemaining be maxBytesToCopy.
1572 size_t totalBytesToCopyRemaining
= maxBytesToCopy
;
1574 // Step 7. Let ready be false.
1577 // Step 8. If maxAlignedBytes > currentAlignedBytes,
1578 if (maxAlignedBytes
> currentAlignedBytes
) {
1579 // Step 8.1. Set totalBytesToCopyRemaining to maxAlignedBytes −
1580 // pullIntoDescriptor’s bytes filled.
1581 totalBytesToCopyRemaining
=
1582 maxAlignedBytes
- aPullIntoDescriptor
->BytesFilled();
1583 // Step 8.2. Set ready to true.
1587 // Step 9. Let queue be controller.[[queue]].
1588 LinkedList
<RefPtr
<ReadableByteStreamQueueEntry
>>& queue
=
1589 aController
->Queue();
1591 // Step 10. While totalBytesToCopyRemaining > 0,
1592 while (totalBytesToCopyRemaining
> 0) {
1593 // Step 10.1 Let headOfQueue be queue[0].
1594 ReadableByteStreamQueueEntry
* headOfQueue
= queue
.getFirst();
1596 // Step 10.2. Let bytesToCopy be min(totalBytesToCopyRemaining,
1597 // headOfQueue’s byte length).
1598 size_t bytesToCopy
=
1599 std::min(totalBytesToCopyRemaining
, headOfQueue
->ByteLength());
1601 // Step 10.3. Let destStart be pullIntoDescriptor’s byte offset +
1602 // pullIntoDescriptor’s bytes filled.
1604 aPullIntoDescriptor
->ByteOffset() + aPullIntoDescriptor
->BytesFilled();
1606 // Step 10.4. Perform !CopyDataBlockBytes(pullIntoDescriptor’s
1607 // buffer.[[ArrayBufferData]], destStart, headOfQueue’s
1608 // buffer.[[ArrayBufferData]], headOfQueue’s byte offset,
1610 JS::Rooted
<JSObject
*> descriptorBuffer(aCx
, aPullIntoDescriptor
->Buffer());
1611 JS::Rooted
<JSObject
*> queueBuffer(aCx
, headOfQueue
->Buffer());
1612 if (!JS::ArrayBufferCopyData(aCx
, descriptorBuffer
, destStart
, queueBuffer
,
1613 headOfQueue
->ByteOffset(), bytesToCopy
)) {
1614 aRv
.StealExceptionFromJSContext(aCx
);
1618 // Step 10.5. If headOfQueue’s byte length is bytesToCopy,
1619 if (headOfQueue
->ByteLength() == bytesToCopy
) {
1620 // Step 10.5.1. Remove queue[0].
1623 // Step 10.6. Otherwise,
1625 // Step 10.6.1 Set headOfQueue’s byte offset to
1626 // headOfQueue’s byte offset + bytesToCopy.
1627 headOfQueue
->SetByteOffset(headOfQueue
->ByteOffset() + bytesToCopy
);
1628 // Step 10.6.2 Set headOfQueue’s byte length to
1629 // headOfQueue’s byte length − bytesToCopy.
1630 headOfQueue
->SetByteLength(headOfQueue
->ByteLength() - bytesToCopy
);
1633 // Step 10.7. Set controller.[[queueTotalSize]] to
1634 // controller.[[queueTotalSize]] − bytesToCopy.
1635 aController
->SetQueueTotalSize(aController
->QueueTotalSize() -
1636 (double)bytesToCopy
);
1638 // Step 10.8, Perform
1639 // !ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller,
1640 // bytesToCopy, pullIntoDescriptor).
1641 ReadableByteStreamControllerFillHeadPullIntoDescriptor(
1642 aController
, bytesToCopy
, aPullIntoDescriptor
);
1644 // Step 10.9. Set totalBytesToCopyRemaining to totalBytesToCopyRemaining −
1646 totalBytesToCopyRemaining
= totalBytesToCopyRemaining
- bytesToCopy
;
1649 // Step 11. If ready is false,
1651 // Step 11.1. Assert: controller.[[queueTotalSize]] is 0.
1652 MOZ_ASSERT(aController
->QueueTotalSize() == 0);
1654 // Step 11.2. Assert: pullIntoDescriptor’s bytes filled > 0.
1655 MOZ_ASSERT(aPullIntoDescriptor
->BytesFilled() > 0);
1657 // Step 11.3. Assert: pullIntoDescriptor’s bytes filled <
1658 // pullIntoDescriptor’s
1660 MOZ_ASSERT(aPullIntoDescriptor
->BytesFilled() <
1661 aPullIntoDescriptor
->ElementSize());
1664 // Step 12. Return ready.
1668 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-pull-into
1669 void ReadableByteStreamControllerPullInto(
1670 JSContext
* aCx
, ReadableByteStreamController
* aController
,
1671 JS::Handle
<JSObject
*> aView
, ReadIntoRequest
* aReadIntoRequest
,
1673 aRv
.MightThrowJSException();
1675 // Step 1. Let stream be controller.[[stream]].
1676 ReadableStream
* stream
= aController
->Stream();
1678 // Step 2. Let elementSize be 1.
1679 size_t elementSize
= 1;
1681 // Step 3. Let ctor be %DataView%.
1682 PullIntoDescriptor::Constructor ctor
=
1683 PullIntoDescriptor::Constructor::DataView
;
1685 // Step 4. If view has a [[TypedArrayName]] internal slot (i.e., it is not a
1687 if (JS_IsTypedArrayObject(aView
)) {
1688 // Step 4.1. Set elementSize to the element size specified in the typed
1689 // array constructors table for view.[[TypedArrayName]].
1690 JS::Scalar::Type type
= JS_GetArrayBufferViewType(aView
);
1691 elementSize
= JS::Scalar::byteSize(type
);
1693 // Step 4.2 Set ctor to the constructor specified in the typed array
1694 // constructors table for view.[[TypedArrayName]].
1695 ctor
= PullIntoDescriptor::constructorFromScalar(type
);
1698 // Step 5. Let byteOffset be view.[[ByteOffset]].
1699 size_t byteOffset
= JS_GetArrayBufferViewByteOffset(aView
);
1701 // Step 6. Let byteLength be view.[[ByteLength]].
1702 size_t byteLength
= JS_GetArrayBufferViewByteLength(aView
);
1704 // Step 7. Let bufferResult be
1705 // TransferArrayBuffer(view.[[ViewedArrayBuffer]]).
1707 JS::Rooted
<JSObject
*> viewedArrayBuffer(
1708 aCx
, JS_GetArrayBufferViewBuffer(aCx
, aView
, &isShared
));
1709 if (!viewedArrayBuffer
) {
1710 aRv
.StealExceptionFromJSContext(aCx
);
1713 JS::Rooted
<JSObject
*> bufferResult(
1714 aCx
, TransferArrayBuffer(aCx
, viewedArrayBuffer
));
1716 // Step 8. If bufferResult is an abrupt completion,
1717 if (!bufferResult
) {
1718 JS::Rooted
<JS::Value
> pendingException(aCx
);
1719 if (!JS_GetPendingException(aCx
, &pendingException
)) {
1720 // This means an un-catchable exception. Use StealExceptionFromJSContext
1721 // to setup aRv properly.
1722 aRv
.StealExceptionFromJSContext(aCx
);
1726 // It's not expliclitly stated, but I assume the intention here is that
1727 // we perform a normal completion here; we also need to clear the
1728 // exception state anyhow to succesfully run ErrorSteps.
1729 JS_ClearPendingException(aCx
);
1731 // Step 8.1. Perform readIntoRequest’s error steps, given
1732 // bufferResult.[[Value]].
1733 aReadIntoRequest
->ErrorSteps(aCx
, pendingException
, aRv
);
1735 // Step 8.2. Return.
1739 // Step 9. Let buffer be bufferResult.[[Value]].
1740 JS::Rooted
<JSObject
*> buffer(aCx
, bufferResult
);
1742 // Step 10. Let pullIntoDescriptor be a new pull-into descriptor with
1744 // buffer byte length: buffer.[[ArrayBufferByteLength]],
1745 // byte offset: byteOffset,
1746 // byte length: byteLength,
1748 // element size: elementSize,
1749 // view constructor: ctor,
1750 // and reader type: "byob".
1751 RefPtr
<PullIntoDescriptor
> pullIntoDescriptor
= new PullIntoDescriptor(
1752 buffer
, JS::GetArrayBufferByteLength(buffer
), byteOffset
, byteLength
, 0,
1753 elementSize
, ctor
, ReaderType::BYOB
);
1755 // Step 11. If controller.[[pendingPullIntos]] is not empty,
1756 if (!aController
->PendingPullIntos().isEmpty()) {
1757 // Step 11.1. Append pullIntoDescriptor to controller.[[pendingPullIntos]].
1758 aController
->PendingPullIntos().insertBack(pullIntoDescriptor
);
1760 // Step 11.2. Perform !ReadableStreamAddReadIntoRequest(stream,
1761 // readIntoRequest).
1762 ReadableStreamAddReadIntoRequest(stream
, aReadIntoRequest
);
1764 // Step 11.3. Return.
1768 // Step 12. If stream.[[state]] is "closed",
1769 if (stream
->State() == ReadableStream::ReaderState::Closed
) {
1770 // Step 12.1. Let emptyView be !Construct(ctor, « pullIntoDescriptor’s
1771 // buffer, pullIntoDescriptor’s byte offset, 0 »).
1772 JS::Rooted
<JSObject
*> pullIntoBuffer(aCx
, pullIntoDescriptor
->Buffer());
1773 JS::Rooted
<JSObject
*> emptyView(
1775 ConstructFromPullIntoConstructor(aCx
, ctor
, pullIntoBuffer
,
1776 pullIntoDescriptor
->ByteOffset(), 0));
1778 aRv
.StealExceptionFromJSContext(aCx
);
1782 // Step 12.2. Perform readIntoRequest’s close steps, given emptyView.
1783 JS::Rooted
<JS::Value
> emptyViewValue(aCx
, JS::ObjectValue(*emptyView
));
1784 aReadIntoRequest
->CloseSteps(aCx
, emptyViewValue
, aRv
);
1786 // Step 12.3. Return.
1790 // Step 13,. If controller.[[queueTotalSize]] > 0,
1791 if (aController
->QueueTotalSize() > 0) {
1793 // !ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller,
1794 // pullIntoDescriptor) is true,
1795 bool ready
= ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(
1796 aCx
, aController
, pullIntoDescriptor
, aRv
);
1801 // Step 13.1.1 Let filledView be
1802 // !ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor).
1803 JS::Rooted
<JSObject
*> filledView(
1804 aCx
, ReadableByteStreamControllerConvertPullIntoDescriptor(
1805 aCx
, pullIntoDescriptor
, aRv
));
1809 // Step 13.1.2. Perform
1810 // !ReadableByteStreamControllerHandleQueueDrain(controller).
1811 ReadableByteStreamControllerHandleQueueDrain(aCx
, aController
, aRv
);
1815 // Step 13.1.3. Perform readIntoRequest’s chunk steps, given filledView.
1816 JS::Rooted
<JS::Value
> filledViewValue(aCx
, JS::ObjectValue(*filledView
));
1817 aReadIntoRequest
->ChunkSteps(aCx
, filledViewValue
, aRv
);
1818 // Step 13.1.4. Return.
1822 // Step 13.2 If controller.[[closeRequested]] is true,
1823 if (aController
->CloseRequested()) {
1824 // Step 13.2.1. Let e be a TypeError exception.
1825 ErrorResult typeError
;
1826 typeError
.ThrowTypeError("Close Requested True during Pull Into");
1828 JS::Rooted
<JS::Value
> e(aCx
);
1829 MOZ_RELEASE_ASSERT(ToJSValue(aCx
, std::move(typeError
), &e
));
1831 // Step 13.2.2. Perform !ReadableByteStreamControllerError(controller, e).
1832 ReadableByteStreamControllerError(aController
, e
, aRv
);
1837 // Step 13.2.3. Perform readIntoRequest’s error steps, given e.
1838 aReadIntoRequest
->ErrorSteps(aCx
, e
, aRv
);
1840 // Step 13.2.4. Return.
1845 // Step 14. Append pullIntoDescriptor to controller.[[pendingPullIntos]].
1846 aController
->PendingPullIntos().insertBack(pullIntoDescriptor
);
1848 // Step 15. Perform !ReadableStreamAddReadIntoRequest(stream,
1849 // readIntoRequest).
1850 ReadableStreamAddReadIntoRequest(stream
, aReadIntoRequest
);
1853 // !ReadableByteStreamControllerCallPullIfNeeded(controller).
1854 ReadableByteStreamControllerCallPullIfNeeded(aCx
, aController
, aRv
);
1857 // https://streams.spec.whatwg.org/#set-up-readable-byte-stream-controller
1858 void SetUpReadableByteStreamController(
1859 JSContext
* aCx
, ReadableStream
* aStream
,
1860 ReadableByteStreamController
* aController
,
1861 UnderlyingSourceAlgorithmsBase
* aAlgorithms
, double aHighWaterMark
,
1862 Maybe
<uint64_t> aAutoAllocateChunkSize
, ErrorResult
& aRv
) {
1863 // Step 1. Assert: stream.[[controller]] is undefined.
1864 MOZ_ASSERT(!aStream
->Controller());
1866 // Step 2. If autoAllocateChunkSize is not undefined,
1867 // Step 2.1. Assert: ! IsInteger(autoAllocateChunkSize) is true. Implicit
1868 // Step 2.2. Assert: autoAllocateChunkSize is positive. (Implicit by
1871 // Step 3. Set controller.[[stream]] to stream.
1872 aController
->SetStream(aStream
);
1874 // Step 4. Set controller.[[pullAgain]] and controller.[[pulling]] to false.
1875 aController
->SetPullAgain(false);
1876 aController
->SetPulling(false);
1878 // Step 5. Set controller.[[byobRequest]] to null.
1879 aController
->SetByobRequest(nullptr);
1881 // Step 6. Perform !ResetQueue(controller).
1882 ResetQueue(aController
);
1884 // Step 7. Set controller.[[closeRequested]] and controller.[[started]] to
1886 aController
->SetCloseRequested(false);
1887 aController
->SetStarted(false);
1889 // Step 8. Set controller.[[strategyHWM]] to highWaterMark.
1890 aController
->SetStrategyHWM(aHighWaterMark
);
1892 // Step 9. Set controller.[[pullAlgorithm]] to pullAlgorithm.
1893 // Step 10. Set controller.[[cancelAlgorithm]] to cancelAlgorithm.
1894 aController
->SetAlgorithms(*aAlgorithms
);
1896 // Step 11. Set controller.[[autoAllocateChunkSize]] to autoAllocateChunkSize.
1897 aController
->SetAutoAllocateChunkSize(aAutoAllocateChunkSize
);
1899 // Step 12. Set controller.[[pendingPullIntos]] to a new empty list.
1900 aController
->PendingPullIntos().clear();
1902 // Step 13. Set stream.[[controller]] to controller.
1903 aStream
->SetController(*aController
);
1905 // Step 14. Let startResult be the result of performing startAlgorithm.
1906 JS::Rooted
<JS::Value
> startResult(aCx
, JS::UndefinedValue());
1907 RefPtr
<ReadableStreamController
> controller
= aController
;
1908 aAlgorithms
->StartCallback(aCx
, *controller
, &startResult
, aRv
);
1913 // Let startPromise be a promise resolved with startResult.
1914 RefPtr
<Promise
> startPromise
=
1915 Promise::CreateInfallible(aStream
->GetParentObject());
1916 startPromise
->MaybeResolve(startResult
);
1919 startPromise
->AddCallbacksWithCycleCollectedArgs(
1920 [](JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
, ErrorResult
& aRv
,
1921 ReadableByteStreamController
* aController
)
1922 MOZ_CAN_RUN_SCRIPT_BOUNDARY
{
1923 MOZ_ASSERT(aController
);
1926 aController
->SetStarted(true);
1929 aController
->SetPulling(false);
1932 aController
->SetPullAgain(false);
1935 ReadableByteStreamControllerCallPullIfNeeded(
1936 aCx
, MOZ_KnownLive(aController
), aRv
);
1938 [](JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
, ErrorResult
& aRv
,
1939 ReadableByteStreamController
* aController
) {
1941 ReadableByteStreamControllerError(aController
, aValue
, aRv
);
1943 RefPtr(aController
));
1946 // https://streams.spec.whatwg.org/#set-up-readable-byte-stream-controller-from-underlying-source
1947 void SetUpReadableByteStreamControllerFromUnderlyingSource(
1948 JSContext
* aCx
, ReadableStream
* aStream
,
1949 JS::Handle
<JSObject
*> aUnderlyingSource
,
1950 UnderlyingSource
& aUnderlyingSourceDict
, double aHighWaterMark
,
1952 // Step 1. Let controller be a new ReadableByteStreamController.
1954 MakeRefPtr
<ReadableByteStreamController
>(aStream
->GetParentObject());
1957 auto algorithms
= MakeRefPtr
<UnderlyingSourceAlgorithms
>(
1958 aStream
->GetParentObject(), aUnderlyingSource
, aUnderlyingSourceDict
);
1960 // Step 8. Let autoAllocateChunkSize be
1961 // underlyingSourceDict["autoAllocateChunkSize"], if it exists, or undefined
1963 Maybe
<uint64_t> autoAllocateChunkSize
= mozilla::Nothing();
1964 if (aUnderlyingSourceDict
.mAutoAllocateChunkSize
.WasPassed()) {
1965 uint64_t value
= aUnderlyingSourceDict
.mAutoAllocateChunkSize
.Value();
1966 // Step 9. If autoAllocateChunkSize is 0, then throw a TypeError
1969 aRv
.ThrowTypeError("autoAllocateChunkSize can not be zero.");
1972 autoAllocateChunkSize
= mozilla::Some(value
);
1975 // Step 10. Perform ? SetUpReadableByteStreamController(stream, controller,
1976 // startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark,
1977 // autoAllocateChunkSize).
1978 SetUpReadableByteStreamController(aCx
, aStream
, controller
, algorithms
,
1979 aHighWaterMark
, autoAllocateChunkSize
, aRv
);
1982 } // namespace streams_abstract
1984 } // namespace mozilla::dom