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 // 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
)
54 ReadableByteStreamQueueEntry(JS::Handle
<JSObject
*> aBuffer
,
55 size_t aByteOffset
, size_t aByteLength
)
56 : mBuffer(aBuffer
), mByteOffset(aByteOffset
), mByteLength(aByteLength
) {
57 mozilla::HoldJSObjects(this);
60 JSObject
* Buffer() const { return mBuffer
; }
61 void SetBuffer(JS::Handle
<JSObject
*> aBuffer
) { mBuffer
= aBuffer
; }
63 size_t ByteOffset() const { return mByteOffset
; }
64 void SetByteOffset(size_t aByteOffset
) { mByteOffset
= aByteOffset
; }
66 size_t ByteLength() const { return mByteLength
; }
67 void SetByteLength(size_t aByteLength
) { mByteLength
= aByteLength
; }
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
;
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;
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;
82 ~ReadableByteStreamQueueEntry() { mozilla::DropJSObjects(this); }
85 NS_IMPL_CYCLE_COLLECTION_WITH_JS_MEMBERS(ReadableByteStreamQueueEntry
, (),
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
)
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
100 static Constructor
constructorFromScalar(JS::Scalar::Type 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
)
108 case JS::Scalar::Int64
:
109 case JS::Scalar::Simd128
:
110 case JS::Scalar::MaxTypedArrayViewType
:
113 MOZ_CRASH("Unexpected Scalar::Type");
116 PullIntoDescriptor(JS::Handle
<JSObject
*> aBuffer
, uint64_t aBufferByteLength
,
117 uint64_t aByteOffset
, uint64_t aByteLength
,
118 uint64_t aBytesFilled
, uint64_t aElementSize
,
119 Constructor aViewConstructor
, ReaderType aReaderType
)
121 mBufferByteLength(aBufferByteLength
),
122 mByteOffset(aByteOffset
),
123 mByteLength(aByteLength
),
124 mBytesFilled(aBytesFilled
),
125 mElementSize(aElementSize
),
126 mViewConstructor(aViewConstructor
),
127 mReaderType(aReaderType
) {
128 mozilla::HoldJSObjects(this);
131 JSObject
* Buffer() const { return mBuffer
; }
132 void SetBuffer(JS::Handle
<JSObject
*> aBuffer
) { mBuffer
= aBuffer
; }
134 uint64_t BufferByteLength() const { return mBufferByteLength
; }
135 void SetBufferByteLength(const uint64_t aBufferByteLength
) {
136 mBufferByteLength
= aBufferByteLength
;
139 uint64_t ByteOffset() const { return mByteOffset
; }
140 void SetByteOffset(const uint64_t aByteOffset
) { mByteOffset
= aByteOffset
; }
142 uint64_t ByteLength() const { return mByteLength
; }
143 void SetByteLength(const uint64_t aByteLength
) { mByteLength
= aByteLength
; }
145 uint64_t BytesFilled() const { return mBytesFilled
; }
146 void SetBytesFilled(const uint64_t aBytesFilled
) {
147 mBytesFilled
= aBytesFilled
;
150 uint64_t ElementSize() const { return mElementSize
; }
151 void SetElementSize(const uint64_t aElementSize
) {
152 mElementSize
= aElementSize
;
155 Constructor
ViewConstructor() const { return mViewConstructor
; }
157 // Note: Named GetReaderType to avoid name conflict with type.
158 ReaderType
GetReaderType() const { return mReaderType
; }
159 void SetReaderType(const ReaderType aReaderType
) {
160 mReaderType
= aReaderType
;
164 JS::Heap
<JSObject
*> mBuffer
;
165 uint64_t mBufferByteLength
= 0;
166 uint64_t mByteOffset
= 0;
167 uint64_t mByteLength
= 0;
168 uint64_t mBytesFilled
= 0;
169 uint64_t mElementSize
= 0;
170 Constructor mViewConstructor
;
171 ReaderType mReaderType
;
173 ~PullIntoDescriptor() { mozilla::DropJSObjects(this); }
176 NS_IMPL_CYCLE_COLLECTION_WITH_JS_MEMBERS(PullIntoDescriptor
, (), (mBuffer
));
178 NS_IMPL_CYCLE_COLLECTION_CLASS(ReadableByteStreamController
)
179 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ReadableByteStreamController
,
180 ReadableStreamController
)
181 NS_IMPL_CYCLE_COLLECTION_UNLINK(mByobRequest
, mQueue
, mPendingPullIntos
)
182 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
183 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
185 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ReadableByteStreamController
,
186 ReadableStreamController
)
187 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mByobRequest
, mQueue
, mPendingPullIntos
)
188 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
190 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(ReadableByteStreamController
,
191 ReadableStreamController
)
192 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
193 NS_IMPL_CYCLE_COLLECTION_TRACE_END
195 NS_IMPL_ADDREF_INHERITED(ReadableByteStreamController
, ReadableStreamController
)
196 NS_IMPL_RELEASE_INHERITED(ReadableByteStreamController
,
197 ReadableStreamController
)
198 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ReadableByteStreamController
)
199 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
200 NS_INTERFACE_MAP_END_INHERITING(ReadableStreamController
)
202 ReadableByteStreamController::ReadableByteStreamController(
203 nsIGlobalObject
* aGlobal
)
204 : ReadableStreamController(aGlobal
) {}
206 ReadableByteStreamController::~ReadableByteStreamController() = default;
208 void ReadableByteStreamController::ClearQueue() { mQueue
.clear(); }
210 void ReadableByteStreamController::ClearPendingPullIntos() {
211 mPendingPullIntos
.clear();
214 namespace streams_abstract
{
215 // https://streams.spec.whatwg.org/#abstract-opdef-readablebytestreamcontrollergetbyobrequest
216 already_AddRefed
<ReadableStreamBYOBRequest
>
217 ReadableByteStreamControllerGetBYOBRequest(
218 JSContext
* aCx
, ReadableByteStreamController
* aController
,
221 if (!aController
->GetByobRequest() &&
222 !aController
->PendingPullIntos().isEmpty()) {
224 PullIntoDescriptor
* firstDescriptor
=
225 aController
->PendingPullIntos().getFirst();
228 aRv
.MightThrowJSException();
229 JS::Rooted
<JSObject
*> buffer(aCx
, firstDescriptor
->Buffer());
230 JS::Rooted
<JSObject
*> view(
231 aCx
, JS_NewUint8ArrayWithBuffer(
233 firstDescriptor
->ByteOffset() + firstDescriptor
->BytesFilled(),
234 int64_t(firstDescriptor
->ByteLength() -
235 firstDescriptor
->BytesFilled())));
237 aRv
.StealExceptionFromJSContext(aCx
);
242 RefPtr
<ReadableStreamBYOBRequest
> byobRequest
=
243 new ReadableStreamBYOBRequest(aController
->GetParentObject());
246 byobRequest
->SetController(aController
);
249 byobRequest
->SetView(view
);
252 aController
->SetByobRequest(byobRequest
);
256 RefPtr
<ReadableStreamBYOBRequest
> request(aController
->GetByobRequest());
257 return request
.forget();
259 } // namespace streams_abstract
261 already_AddRefed
<ReadableStreamBYOBRequest
>
262 ReadableByteStreamController::GetByobRequest(JSContext
* aCx
, ErrorResult
& aRv
) {
263 return ReadableByteStreamControllerGetBYOBRequest(aCx
, this, aRv
);
266 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-get-desired-size
267 Nullable
<double> ReadableByteStreamControllerGetDesiredSize(
268 const ReadableByteStreamController
* aController
) {
270 ReadableStream::ReaderState state
= aController
->Stream()->State();
273 if (state
== ReadableStream::ReaderState::Errored
) {
278 if (state
== ReadableStream::ReaderState::Closed
) {
283 return aController
->StrategyHWM() - aController
->QueueTotalSize();
286 Nullable
<double> ReadableByteStreamController::GetDesiredSize() const {
288 return ReadableByteStreamControllerGetDesiredSize(this);
291 JSObject
* ReadableByteStreamController::WrapObject(
292 JSContext
* aCx
, JS::Handle
<JSObject
*> aGivenProto
) {
293 return ReadableByteStreamController_Binding::Wrap(aCx
, this, aGivenProto
);
296 namespace streams_abstract
{
298 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-invalidate-byob-request
299 static void ReadableByteStreamControllerInvalidateBYOBRequest(
300 ReadableByteStreamController
* aController
) {
302 if (!aController
->GetByobRequest()) {
307 aController
->GetByobRequest()->SetController(nullptr);
310 aController
->GetByobRequest()->SetView(nullptr);
313 aController
->SetByobRequest(nullptr);
316 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-clear-pending-pull-intos
317 void ReadableByteStreamControllerClearPendingPullIntos(
318 ReadableByteStreamController
* aController
) {
320 ReadableByteStreamControllerInvalidateBYOBRequest(aController
);
323 aController
->ClearPendingPullIntos();
326 // https://streams.spec.whatwg.org/#reset-queue
327 void ResetQueue(ReadableByteStreamController
* aContainer
) {
328 // Step 1. Implied by type.
330 aContainer
->ClearQueue();
333 aContainer
->SetQueueTotalSize(0);
336 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-clear-algorithms
337 void ReadableByteStreamControllerClearAlgorithms(
338 ReadableByteStreamController
* aController
) {
339 // Step 1. Set controller.[[pullAlgorithm]] to undefined.
340 // Step 2. Set controller.[[cancelAlgorithm]] to undefined.
341 aController
->ClearAlgorithms();
344 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-error
345 void ReadableByteStreamControllerError(
346 ReadableByteStreamController
* aController
, JS::Handle
<JS::Value
> aValue
,
348 // Step 1. Let stream be controller.[[stream]].
349 ReadableStream
* stream
= aController
->Stream();
351 // Step 2. If stream.[[state]] is not "readable", return.
352 if (stream
->State() != ReadableStream::ReaderState::Readable
) {
357 // !ReadableByteStreamControllerClearPendingPullIntos(controller).
358 ReadableByteStreamControllerClearPendingPullIntos(aController
);
360 // Step 4. Perform !ResetQueue(controller).
361 ResetQueue(aController
);
363 // Step 5. Perform !ReadableByteStreamControllerClearAlgorithms(controller).
364 ReadableByteStreamControllerClearAlgorithms(aController
);
366 // Step 6. Perform !ReadableStreamError(stream, e).
368 if (!jsapi
.Init(aController
->GetParentObject())) {
371 ReadableStreamError(jsapi
.cx(), stream
, aValue
, aRv
);
374 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-close
375 void ReadableByteStreamControllerClose(
376 JSContext
* aCx
, ReadableByteStreamController
* aController
,
379 RefPtr
<ReadableStream
> stream
= aController
->Stream();
382 if (aController
->CloseRequested() ||
383 stream
->State() != ReadableStream::ReaderState::Readable
) {
388 if (aController
->QueueTotalSize() > 0) {
390 aController
->SetCloseRequested(true);
396 if (!aController
->PendingPullIntos().isEmpty()) {
398 PullIntoDescriptor
* firstPendingPullInto
=
399 aController
->PendingPullIntos().getFirst();
401 if (firstPendingPullInto
->BytesFilled() > 0) {
404 rv
.ThrowTypeError("Leftover Bytes");
406 JS::Rooted
<JS::Value
> exception(aCx
);
407 MOZ_ALWAYS_TRUE(ToJSValue(aCx
, std::move(rv
), &exception
));
410 ReadableByteStreamControllerError(aController
, exception
, aRv
);
415 aRv
.MightThrowJSException();
416 aRv
.ThrowJSException(aCx
, exception
);
422 ReadableByteStreamControllerClearAlgorithms(aController
);
425 ReadableStreamClose(aCx
, stream
, aRv
);
428 } // namespace streams_abstract
430 // https://streams.spec.whatwg.org/#rbs-controller-close
431 void ReadableByteStreamController::Close(JSContext
* aCx
, ErrorResult
& aRv
) {
433 if (mCloseRequested
) {
434 aRv
.ThrowTypeError("Close already requested");
439 if (Stream()->State() != ReadableStream::ReaderState::Readable
) {
440 aRv
.ThrowTypeError("Closing un-readable stream controller");
445 ReadableByteStreamControllerClose(aCx
, this, aRv
);
448 namespace streams_abstract
{
450 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-enqueue-chunk-to-queue
451 void ReadableByteStreamControllerEnqueueChunkToQueue(
452 ReadableByteStreamController
* aController
,
453 JS::Handle
<JSObject
*> aTransferredBuffer
, size_t aByteOffset
,
454 size_t aByteLength
) {
456 RefPtr
<ReadableByteStreamQueueEntry
> queueEntry
=
457 new ReadableByteStreamQueueEntry(aTransferredBuffer
, aByteOffset
,
459 aController
->Queue().insertBack(queueEntry
);
462 aController
->AddToQueueTotalSize(double(aByteLength
));
465 // https://streams.spec.whatwg.org/#abstract-opdef-readablebytestreamcontrollerenqueueclonedchunktoqueue
466 void ReadableByteStreamControllerEnqueueClonedChunkToQueue(
467 JSContext
* aCx
, ReadableByteStreamController
* aController
,
468 JS::Handle
<JSObject
*> aBuffer
, size_t aByteOffset
, size_t aByteLength
,
470 // Step 1. Let cloneResult be CloneArrayBuffer(buffer, byteOffset, byteLength,
472 aRv
.MightThrowJSException();
473 JS::Rooted
<JSObject
*> cloneResult(
474 aCx
, JS::ArrayBufferClone(aCx
, aBuffer
, aByteOffset
, aByteLength
));
476 // Step 2. If cloneResult is an abrupt completion,
478 JS::Rooted
<JS::Value
> exception(aCx
);
479 if (!JS_GetPendingException(aCx
, &exception
)) {
480 // Uncatchable exception; we should mark aRv and return.
481 aRv
.StealExceptionFromJSContext(aCx
);
484 JS_ClearPendingException(aCx
);
486 // Step 2.1. Perform ! ReadableByteStreamControllerError(controller,
487 // cloneResult.[[Value]]).
488 ReadableByteStreamControllerError(aController
, exception
, aRv
);
493 // Step 2.2. Return cloneResult.
494 aRv
.ThrowJSException(aCx
, exception
);
499 // ReadableByteStreamControllerEnqueueChunkToQueue(controller,
500 // cloneResult.[[Value]], 0, byteLength).
501 ReadableByteStreamControllerEnqueueChunkToQueue(aController
, cloneResult
, 0,
505 already_AddRefed
<PullIntoDescriptor
>
506 ReadableByteStreamControllerShiftPendingPullInto(
507 ReadableByteStreamController
* aController
);
509 // https://streams.spec.whatwg.org/#abstract-opdef-readablebytestreamcontrollerenqueuedetachedpullintotoqueue
510 void ReadableByteStreamControllerEnqueueDetachedPullIntoToQueue(
511 JSContext
* aCx
, ReadableByteStreamController
* aController
,
512 PullIntoDescriptor
* aPullIntoDescriptor
, ErrorResult
& aRv
) {
513 // Step 1. Assert: pullIntoDescriptor’s reader type is "none".
514 MOZ_ASSERT(aPullIntoDescriptor
->GetReaderType() == ReaderType::None
);
516 // Step 2. If pullIntoDescriptor’s bytes filled > 0,
517 // perform ? ReadableByteStreamControllerEnqueueClonedChunkToQueue(controller,
518 // pullIntoDescriptor’s buffer, pullIntoDescriptor’s byte offset,
519 // pullIntoDescriptor’s bytes filled).
520 if (aPullIntoDescriptor
->BytesFilled() > 0) {
521 JS::Rooted
<JSObject
*> buffer(aCx
, aPullIntoDescriptor
->Buffer());
522 ReadableByteStreamControllerEnqueueClonedChunkToQueue(
523 aCx
, aController
, buffer
, aPullIntoDescriptor
->ByteOffset(),
524 aPullIntoDescriptor
->BytesFilled(), aRv
);
531 // ReadableByteStreamControllerShiftPendingPullInto(controller).
532 RefPtr
<PullIntoDescriptor
> discarded
=
533 ReadableByteStreamControllerShiftPendingPullInto(aController
);
537 // https://streams.spec.whatwg.org/#readable-stream-get-num-read-into-requests
538 static size_t ReadableStreamGetNumReadIntoRequests(ReadableStream
* aStream
) {
540 MOZ_ASSERT(ReadableStreamHasBYOBReader(aStream
));
543 return aStream
->GetReader()->AsBYOB()->ReadIntoRequests().length();
546 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-should-call-pull
547 bool ReadableByteStreamControllerShouldCallPull(
548 ReadableByteStreamController
* aController
) {
549 // Step 1. Let stream be controller.[[stream]].
550 ReadableStream
* stream
= aController
->Stream();
552 // Step 2. If stream.[[state]] is not "readable", return false.
553 if (stream
->State() != ReadableStream::ReaderState::Readable
) {
557 // Step 3. If controller.[[closeRequested]] is true, return false.
558 if (aController
->CloseRequested()) {
562 // Step 4. If controller.[[started]] is false, return false.
563 if (!aController
->Started()) {
567 // Step 5. If ! ReadableStreamHasDefaultReader(stream) is true
568 // and ! ReadableStreamGetNumReadRequests(stream) > 0, return true.
569 if (ReadableStreamHasDefaultReader(stream
) &&
570 ReadableStreamGetNumReadRequests(stream
) > 0) {
574 // Step 6. If ! ReadableStreamHasBYOBReader(stream) is true
575 // and ! ReadableStreamGetNumReadIntoRequests(stream) > 0, return true.
576 if (ReadableStreamHasBYOBReader(stream
) &&
577 ReadableStreamGetNumReadIntoRequests(stream
) > 0) {
581 // Step 7. Let desiredSize be
582 // ! ReadableByteStreamControllerGetDesiredSize(controller).
583 Nullable
<double> desiredSize
=
584 ReadableByteStreamControllerGetDesiredSize(aController
);
586 // Step 8. Assert: desiredSize is not null.
587 MOZ_ASSERT(!desiredSize
.IsNull());
589 // Step 9. If desiredSize > 0, return true.
590 // Step 10. Return false.
591 return desiredSize
.Value() > 0;
594 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-call-pull-if-needed
595 void ReadableByteStreamControllerCallPullIfNeeded(
596 JSContext
* aCx
, ReadableByteStreamController
* aController
,
599 bool shouldPull
= ReadableByteStreamControllerShouldCallPull(aController
);
607 if (aController
->Pulling()) {
608 aController
->SetPullAgain(true);
613 MOZ_ASSERT(!aController
->PullAgain());
616 aController
->SetPulling(true);
619 RefPtr
<ReadableStreamController
> controller(aController
);
620 RefPtr
<UnderlyingSourceAlgorithmsBase
> algorithms
=
621 aController
->GetAlgorithms();
622 RefPtr
<Promise
> pullPromise
= algorithms
->PullCallback(aCx
, *controller
, aRv
);
628 pullPromise
->AddCallbacksWithCycleCollectedArgs(
629 [](JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
, ErrorResult
& aRv
,
630 ReadableByteStreamController
* aController
)
631 MOZ_CAN_RUN_SCRIPT_BOUNDARY
{
633 aController
->SetPulling(false);
635 if (aController
->PullAgain()) {
637 aController
->SetPullAgain(false);
640 ReadableByteStreamControllerCallPullIfNeeded(
641 aCx
, MOZ_KnownLive(aController
), aRv
);
644 [](JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
, ErrorResult
& aRv
,
645 ReadableByteStreamController
* aController
) {
647 ReadableByteStreamControllerError(aController
, aValue
, aRv
);
649 RefPtr(aController
));
652 bool ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(
653 JSContext
* aCx
, ReadableByteStreamController
* aController
,
654 PullIntoDescriptor
* aPullIntoDescriptor
, ErrorResult
& aRv
);
656 JSObject
* ReadableByteStreamControllerConvertPullIntoDescriptor(
657 JSContext
* aCx
, PullIntoDescriptor
* pullIntoDescriptor
, ErrorResult
& aRv
);
659 // https://streams.spec.whatwg.org/#readable-stream-fulfill-read-into-request
661 void ReadableStreamFulfillReadIntoRequest(JSContext
* aCx
,
662 ReadableStream
* aStream
,
663 JS::Handle
<JS::Value
> aChunk
,
664 bool done
, ErrorResult
& aRv
) {
665 // Step 1. Assert: !ReadableStreamHasBYOBReader(stream) is true.
666 MOZ_ASSERT(ReadableStreamHasBYOBReader(aStream
));
668 // Step 2. Let reader be stream.[[reader]].
669 ReadableStreamBYOBReader
* reader
= aStream
->GetReader()->AsBYOB();
671 // Step 3. Assert: reader.[[readIntoRequests]] is not empty.
672 MOZ_ASSERT(!reader
->ReadIntoRequests().isEmpty());
674 // Step 4. Let readIntoRequest be reader.[[readIntoRequests]][0].
675 // Step 5. Remove readIntoRequest from reader.[[readIntoRequests]].
676 RefPtr
<ReadIntoRequest
> readIntoRequest
=
677 reader
->ReadIntoRequests().popFirst();
679 // Step 6. If done is true, perform readIntoRequest’s close steps, given
682 readIntoRequest
->CloseSteps(aCx
, aChunk
, aRv
);
686 // Step 7. Otherwise, perform readIntoRequest’s chunk steps, given chunk.
687 readIntoRequest
->ChunkSteps(aCx
, aChunk
, aRv
);
690 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-commit-pull-into-descriptor
692 void ReadableByteStreamControllerCommitPullIntoDescriptor(
693 JSContext
* aCx
, ReadableStream
* aStream
,
694 PullIntoDescriptor
* pullIntoDescriptor
, ErrorResult
& aRv
) {
695 // Step 1. Assert: stream.[[state]] is not "errored".
696 MOZ_ASSERT(aStream
->State() != ReadableStream::ReaderState::Errored
);
698 // Step 2. Assert: pullIntoDescriptor.reader type is not "none".
699 MOZ_ASSERT(pullIntoDescriptor
->GetReaderType() != ReaderType::None
);
701 // Step 3. Let done be false.
704 // Step 4. If stream.[[state]] is "closed",
705 if (aStream
->State() == ReadableStream::ReaderState::Closed
) {
706 // Step 4.1. Assert: pullIntoDescriptor’s bytes filled is 0.
707 MOZ_ASSERT(pullIntoDescriptor
->BytesFilled() == 0);
709 // Step 4.2. Set done to true.
713 // Step 5. Let filledView be !
714 // ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor).
715 JS::Rooted
<JSObject
*> filledView(
716 aCx
, ReadableByteStreamControllerConvertPullIntoDescriptor(
717 aCx
, pullIntoDescriptor
, aRv
));
721 JS::Rooted
<JS::Value
> filledViewValue(aCx
, JS::ObjectValue(*filledView
));
723 // Step 6. If pullIntoDescriptor’s reader type is "default",
724 if (pullIntoDescriptor
->GetReaderType() == ReaderType::Default
) {
725 // Step 6.1. Perform !ReadableStreamFulfillReadRequest(stream, filledView,
727 ReadableStreamFulfillReadRequest(aCx
, aStream
, filledViewValue
, done
, aRv
);
731 // Step 7.1. Assert: pullIntoDescriptor’s reader type is "byob".
732 MOZ_ASSERT(pullIntoDescriptor
->GetReaderType() == ReaderType::BYOB
);
734 // Step 7.2 Perform !ReadableStreamFulfillReadIntoRequest(stream, filledView,
736 ReadableStreamFulfillReadIntoRequest(aCx
, aStream
, filledViewValue
, done
,
740 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-process-pull-into-descriptors-using-queue
742 void ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(
743 JSContext
* aCx
, ReadableByteStreamController
* aController
,
745 // Step 1. Assert: controller.[[closeRequested]] is false.
746 MOZ_ASSERT(!aController
->CloseRequested());
748 // Step 2. While controller.[[pendingPullIntos]] is not empty,
749 while (!aController
->PendingPullIntos().isEmpty()) {
750 // Step 2.1 If controller.[[queueTotalSize]] is 0, return.
751 if (aController
->QueueTotalSize() == 0) {
755 // Step 2.2. Let pullIntoDescriptor be controller.[[pendingPullIntos]][0].
756 RefPtr
<PullIntoDescriptor
> pullIntoDescriptor
=
757 aController
->PendingPullIntos().getFirst();
760 // !ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller,
761 // pullIntoDescriptor) is true,
762 bool ready
= ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(
763 aCx
, aController
, pullIntoDescriptor
, aRv
);
769 // Step 2.3.1. Perform
770 // !ReadableByteStreamControllerShiftPendingPullInto(controller).
771 RefPtr
<PullIntoDescriptor
> discardedPullIntoDescriptor
=
772 ReadableByteStreamControllerShiftPendingPullInto(aController
);
774 // Step 2.3.2. Perform
775 // !ReadableByteStreamControllerCommitPullIntoDescriptor(controller.[[stream]],
776 // pullIntoDescriptor).
777 RefPtr
<ReadableStream
> stream(aController
->Stream());
778 ReadableByteStreamControllerCommitPullIntoDescriptor(
779 aCx
, stream
, pullIntoDescriptor
, aRv
);
788 void ReadableByteStreamControllerHandleQueueDrain(
789 JSContext
* aCx
, ReadableByteStreamController
* aController
,
792 // https://streams.spec.whatwg.org/#abstract-opdef-readablebytestreamcontrollerfillreadrequestfromqueue
793 MOZ_CAN_RUN_SCRIPT
void ReadableByteStreamControllerFillReadRequestFromQueue(
794 JSContext
* aCx
, ReadableByteStreamController
* aController
,
795 ReadRequest
* aReadRequest
, ErrorResult
& aRv
) {
796 // Step 1. Assert: controller.[[queueTotalSize]] > 0.
797 MOZ_ASSERT(aController
->QueueTotalSize() > 0);
798 // Also assert that the queue has a non-zero length;
799 MOZ_ASSERT(aController
->Queue().length() > 0);
801 // Step 2. Let entry be controller.[[queue]][0].
802 // Step 3. Remove entry from controller.[[queue]].
803 RefPtr
<ReadableByteStreamQueueEntry
> entry
= aController
->Queue().popFirst();
805 // Assert that we actually got an entry.
808 // Step 4. Set controller.[[queueTotalSize]] to controller.[[queueTotalSize]]
809 // − entry’s byte length.
810 aController
->SetQueueTotalSize(aController
->QueueTotalSize() -
811 double(entry
->ByteLength()));
813 // Step 5. Perform ! ReadableByteStreamControllerHandleQueueDrain(controller).
814 ReadableByteStreamControllerHandleQueueDrain(aCx
, aController
, aRv
);
819 // Step 6. Let view be ! Construct(%Uint8Array%, « entry’s buffer, entry’s
820 // byte offset, entry’s byte length »).
821 aRv
.MightThrowJSException();
822 JS::Rooted
<JSObject
*> buffer(aCx
, entry
->Buffer());
823 JS::Rooted
<JSObject
*> view(
824 aCx
, JS_NewUint8ArrayWithBuffer(aCx
, buffer
, entry
->ByteOffset(),
825 int64_t(entry
->ByteLength())));
827 aRv
.StealExceptionFromJSContext(aCx
);
831 // Step 7. Perform readRequest’s chunk steps, given view.
832 JS::Rooted
<JS::Value
> viewValue(aCx
, JS::ObjectValue(*view
));
833 aReadRequest
->ChunkSteps(aCx
, viewValue
, aRv
);
836 MOZ_CAN_RUN_SCRIPT
void
837 ReadableByteStreamControllerProcessReadRequestsUsingQueue(
838 JSContext
* aCx
, ReadableByteStreamController
* aController
,
840 // Step 1. Let reader be controller.[[stream]].[[reader]].
841 // Step 2. Assert: reader implements ReadableStreamDefaultReader.
842 RefPtr
<ReadableStreamDefaultReader
> reader
=
843 aController
->Stream()->GetDefaultReader();
845 // Step 3. While reader.[[readRequests]] is not empty,
846 while (!reader
->ReadRequests().isEmpty()) {
847 // Step 3.1. If controller.[[queueTotalSize]] is 0, return.
848 if (aController
->QueueTotalSize() == 0) {
852 // Step 3.2. Let readRequest be reader.[[readRequests]][0].
853 // Step 3.3. Remove readRequest from reader.[[readRequests]].
854 RefPtr
<ReadRequest
> readRequest
= reader
->ReadRequests().popFirst();
856 // Step 3.4. Perform !
857 // ReadableByteStreamControllerFillReadRequestFromQueue(controller,
859 ReadableByteStreamControllerFillReadRequestFromQueue(aCx
, aController
,
867 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-enqueue
868 void ReadableByteStreamControllerEnqueue(
869 JSContext
* aCx
, ReadableByteStreamController
* aController
,
870 JS::Handle
<JSObject
*> aChunk
, ErrorResult
& aRv
) {
871 aRv
.MightThrowJSException();
874 RefPtr
<ReadableStream
> stream
= aController
->Stream();
877 if (aController
->CloseRequested() ||
878 stream
->State() != ReadableStream::ReaderState::Readable
) {
884 JS::Rooted
<JSObject
*> buffer(
885 aCx
, JS_GetArrayBufferViewBuffer(aCx
, aChunk
, &isShared
));
887 aRv
.StealExceptionFromJSContext(aCx
);
892 size_t byteOffset
= JS_GetArrayBufferViewByteOffset(aChunk
);
895 size_t byteLength
= JS_GetArrayBufferViewByteLength(aChunk
);
898 if (JS::IsDetachedArrayBufferObject(buffer
)) {
899 aRv
.ThrowTypeError("Detached Array Buffer");
904 JS::Rooted
<JSObject
*> transferredBuffer(aCx
,
905 TransferArrayBuffer(aCx
, buffer
));
906 if (!transferredBuffer
) {
907 aRv
.StealExceptionFromJSContext(aCx
);
912 if (!aController
->PendingPullIntos().isEmpty()) {
914 RefPtr
<PullIntoDescriptor
> firstPendingPullInto
=
915 aController
->PendingPullIntos().getFirst();
918 JS::Rooted
<JSObject
*> pendingBuffer(aCx
, firstPendingPullInto
->Buffer());
919 if (JS::IsDetachedArrayBufferObject(pendingBuffer
)) {
920 aRv
.ThrowTypeError("Pending PullInto has detached buffer");
924 // Step 8.3. Perform !
925 // ReadableByteStreamControllerInvalidateBYOBRequest(controller).
926 ReadableByteStreamControllerInvalidateBYOBRequest(aController
);
928 // Step 8.4. Set firstPendingPullInto’s buffer to !
929 // TransferArrayBuffer(firstPendingPullInto’s buffer).
930 pendingBuffer
= TransferArrayBuffer(aCx
, pendingBuffer
);
931 if (!pendingBuffer
) {
932 aRv
.StealExceptionFromJSContext(aCx
);
935 firstPendingPullInto
->SetBuffer(pendingBuffer
);
937 // Step 8.5. If firstPendingPullInto’s reader type is "none", perform ?
938 // ReadableByteStreamControllerEnqueueDetachedPullIntoToQueue(controller,
939 // firstPendingPullInto).
940 if (firstPendingPullInto
->GetReaderType() == ReaderType::None
) {
941 ReadableByteStreamControllerEnqueueDetachedPullIntoToQueue(
942 aCx
, aController
, firstPendingPullInto
, aRv
);
949 // Step 9. If ! ReadableStreamHasDefaultReader(stream) is true,
950 if (ReadableStreamHasDefaultReader(stream
)) {
951 // Step 9.1. Perform !
952 // ReadableByteStreamControllerProcessReadRequestsUsingQueue(controller).
953 ReadableByteStreamControllerProcessReadRequestsUsingQueue(aCx
, aController
,
959 // Step 9.2. If ! ReadableStreamGetNumReadRequests(stream) is 0,
960 if (ReadableStreamGetNumReadRequests(stream
) == 0) {
961 // Step 9.2.1 Assert: controller.[[pendingPullIntos]] is empty.
962 MOZ_ASSERT(aController
->PendingPullIntos().isEmpty());
964 // Step 9.2.2. Perform !
965 // ReadableByteStreamControllerEnqueueChunkToQueue(controller,
966 // transferredBuffer, byteOffset, byteLength).
967 ReadableByteStreamControllerEnqueueChunkToQueue(
968 aController
, transferredBuffer
, byteOffset
, byteLength
);
970 // Step 9.3. Otherwise,
972 // Step 9.3.1 Assert: controller.[[queue]] is empty.
973 MOZ_ASSERT(aController
->Queue().isEmpty());
975 // Step 9.3.2. If controller.[[pendingPullIntos]] is not empty,
976 if (!aController
->PendingPullIntos().isEmpty()) {
977 // Step 9.3.2.1. Assert: controller.[[pendingPullIntos]][0]'s reader
978 // type is "default".
980 aController
->PendingPullIntos().getFirst()->GetReaderType() ==
981 ReaderType::Default
);
983 // Step 9.3.2.2. Perform !
984 // ReadableByteStreamControllerShiftPendingPullInto(controller).
985 RefPtr
<PullIntoDescriptor
> pullIntoDescriptor
=
986 ReadableByteStreamControllerShiftPendingPullInto(aController
);
987 (void)pullIntoDescriptor
;
990 // Step 9.3.3. Let transferredView be ! Construct(%Uint8Array%, «
991 // transferredBuffer, byteOffset, byteLength »).
992 JS::Rooted
<JSObject
*> transferredView(
993 aCx
, JS_NewUint8ArrayWithBuffer(aCx
, transferredBuffer
, byteOffset
,
994 int64_t(byteLength
)));
995 if (!transferredView
) {
996 aRv
.StealExceptionFromJSContext(aCx
);
1000 // Step 9.3.4. Perform ! ReadableStreamFulfillReadRequest(stream,
1001 // transferredView, false).
1002 JS::Rooted
<JS::Value
> transferredViewValue(
1003 aCx
, JS::ObjectValue(*transferredView
));
1004 ReadableStreamFulfillReadRequest(aCx
, stream
, transferredViewValue
, false,
1011 // Step 10. Otherwise, if ! ReadableStreamHasBYOBReader(stream) is true,
1012 } else if (ReadableStreamHasBYOBReader(stream
)) {
1013 // Step 10.1. Perform !
1014 // ReadableByteStreamControllerEnqueueChunkToQueue(controller,
1015 // transferredBuffer, byteOffset, byteLength).
1016 ReadableByteStreamControllerEnqueueChunkToQueue(
1017 aController
, transferredBuffer
, byteOffset
, byteLength
);
1019 // Step 10.2 Perform !
1020 // ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller).
1021 ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(
1022 aCx
, aController
, aRv
);
1027 // Step 11. Otherwise,
1029 // Step 11.1. Assert: ! IsReadableStreamLocked(stream) is false.
1030 MOZ_ASSERT(!IsReadableStreamLocked(stream
));
1032 // Step 11.2. Perform !
1033 // ReadableByteStreamControllerEnqueueChunkToQueue(controller,
1034 // transferredBuffer, byteOffset, byteLength).
1035 ReadableByteStreamControllerEnqueueChunkToQueue(
1036 aController
, transferredBuffer
, byteOffset
, byteLength
);
1039 // Step 12. Perform !
1040 // ReadableByteStreamControllerCallPullIfNeeded(controller).
1041 ReadableByteStreamControllerCallPullIfNeeded(aCx
, aController
, aRv
);
1044 } // namespace streams_abstract
1046 // https://streams.spec.whatwg.org/#rbs-controller-enqueue
1047 void ReadableByteStreamController::Enqueue(JSContext
* aCx
,
1048 const ArrayBufferView
& aChunk
,
1051 JS::Rooted
<JSObject
*> chunk(aCx
, aChunk
.Obj());
1052 if (JS_GetArrayBufferViewByteLength(chunk
) == 0) {
1053 aRv
.ThrowTypeError("Zero Length View");
1059 JS::Rooted
<JSObject
*> viewedArrayBuffer(
1060 aCx
, JS_GetArrayBufferViewBuffer(aCx
, chunk
, &isShared
));
1061 if (!viewedArrayBuffer
) {
1062 aRv
.StealExceptionFromJSContext(aCx
);
1066 if (JS::GetArrayBufferByteLength(viewedArrayBuffer
) == 0) {
1067 aRv
.ThrowTypeError("Zero Length Buffer");
1072 if (CloseRequested()) {
1073 aRv
.ThrowTypeError("close requested");
1078 if (Stream()->State() != ReadableStream::ReaderState::Readable
) {
1079 aRv
.ThrowTypeError("Not Readable");
1084 ReadableByteStreamControllerEnqueue(aCx
, this, chunk
, aRv
);
1087 // https://streams.spec.whatwg.org/#rbs-controller-error
1088 void ReadableByteStreamController::Error(JSContext
* aCx
,
1089 JS::Handle
<JS::Value
> aErrorValue
,
1092 ReadableByteStreamControllerError(this, aErrorValue
, aRv
);
1095 // https://streams.spec.whatwg.org/#rbs-controller-private-cancel
1096 already_AddRefed
<Promise
> ReadableByteStreamController::CancelSteps(
1097 JSContext
* aCx
, JS::Handle
<JS::Value
> aReason
, ErrorResult
& aRv
) {
1099 ReadableByteStreamControllerClearPendingPullIntos(this);
1105 Optional
<JS::Handle
<JS::Value
>> reason(aCx
, aReason
);
1106 RefPtr
<UnderlyingSourceAlgorithmsBase
> algorithms
= mAlgorithms
;
1107 RefPtr
<Promise
> result
= algorithms
->CancelCallback(aCx
, reason
, aRv
);
1108 if (NS_WARN_IF(aRv
.Failed())) {
1112 ReadableByteStreamControllerClearAlgorithms(this);
1115 return result
.forget();
1118 namespace streams_abstract
{
1119 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-handle-queue-drain
1120 void ReadableByteStreamControllerHandleQueueDrain(
1121 JSContext
* aCx
, ReadableByteStreamController
* aController
,
1124 MOZ_ASSERT(aController
->Stream()->State() ==
1125 ReadableStream::ReaderState::Readable
);
1128 if (aController
->QueueTotalSize() == 0 && aController
->CloseRequested()) {
1130 ReadableByteStreamControllerClearAlgorithms(aController
);
1133 RefPtr
<ReadableStream
> stream
= aController
->Stream();
1134 ReadableStreamClose(aCx
, stream
, aRv
);
1139 ReadableByteStreamControllerCallPullIfNeeded(aCx
, aController
, aRv
);
1141 } // namespace streams_abstract
1143 // https://streams.spec.whatwg.org/#rbs-controller-private-pull
1144 void ReadableByteStreamController::PullSteps(JSContext
* aCx
,
1145 ReadRequest
* aReadRequest
,
1148 ReadableStream
* stream
= Stream();
1151 MOZ_ASSERT(ReadableStreamHasDefaultReader(stream
));
1154 if (QueueTotalSize() > 0) {
1155 // Step 3.1. Assert: ! ReadableStreamGetNumReadRequests ( stream ) is 0.
1156 MOZ_ASSERT(ReadableStreamGetNumReadRequests(stream
) == 0);
1158 // Step 3.2. Perform !
1159 // ReadableByteStreamControllerFillReadRequestFromQueue(this, readRequest).
1160 ReadableByteStreamControllerFillReadRequestFromQueue(aCx
, this,
1163 // Step 3.3. Return.
1168 Maybe
<uint64_t> autoAllocateChunkSize
= AutoAllocateChunkSize();
1171 if (autoAllocateChunkSize
) {
1173 aRv
.MightThrowJSException();
1174 JS::Rooted
<JSObject
*> buffer(
1175 aCx
, JS::NewArrayBuffer(aCx
, *autoAllocateChunkSize
));
1179 JS::Rooted
<JS::Value
> bufferError(aCx
);
1180 if (!JS_GetPendingException(aCx
, &bufferError
)) {
1181 // Uncatchable exception; we should mark aRv and return.
1182 aRv
.StealExceptionFromJSContext(aCx
);
1186 // It's not expliclitly stated, but I assume the intention here is that
1187 // we perform a normal completion here.
1188 JS_ClearPendingException(aCx
);
1190 aReadRequest
->ErrorSteps(aCx
, bufferError
, aRv
);
1197 RefPtr
<PullIntoDescriptor
> pullIntoDescriptor
= new PullIntoDescriptor(
1198 buffer
, *autoAllocateChunkSize
, 0, *autoAllocateChunkSize
, 0, 1,
1199 PullIntoDescriptor::Constructor::Uint8
, ReaderType::Default
);
1202 PendingPullIntos().insertBack(pullIntoDescriptor
);
1206 ReadableStreamAddReadRequest(stream
, aReadRequest
);
1209 ReadableByteStreamControllerCallPullIfNeeded(aCx
, this, aRv
);
1212 // https://streams.spec.whatwg.org/#abstract-opdef-readablebytestreamcontroller-releasesteps
1213 void ReadableByteStreamController::ReleaseSteps() {
1214 // Step 1. If this.[[pendingPullIntos]] is not empty,
1215 if (!PendingPullIntos().isEmpty()) {
1216 // Step 1.1. Let firstPendingPullInto be this.[[pendingPullIntos]][0].
1217 RefPtr
<PullIntoDescriptor
> firstPendingPullInto
=
1218 PendingPullIntos().popFirst();
1220 // Step 1.2. Set firstPendingPullInto’s reader type to "none".
1221 firstPendingPullInto
->SetReaderType(ReaderType::None
);
1223 // Step 1.3. Set this.[[pendingPullIntos]] to the list «
1224 // firstPendingPullInto ».
1225 PendingPullIntos().clear();
1226 PendingPullIntos().insertBack(firstPendingPullInto
);
1230 namespace streams_abstract
{
1232 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-shift-pending-pull-into
1233 already_AddRefed
<PullIntoDescriptor
>
1234 ReadableByteStreamControllerShiftPendingPullInto(
1235 ReadableByteStreamController
* aController
) {
1237 MOZ_ASSERT(!aController
->GetByobRequest());
1240 RefPtr
<PullIntoDescriptor
> descriptor
=
1241 aController
->PendingPullIntos().popFirst();
1244 return descriptor
.forget();
1247 JSObject
* ConstructFromPullIntoConstructor(
1248 JSContext
* aCx
, PullIntoDescriptor::Constructor constructor
,
1249 JS::Handle
<JSObject
*> buffer
, size_t byteOffset
, size_t length
) {
1250 switch (constructor
) {
1251 case PullIntoDescriptor::Constructor::DataView
:
1252 return JS_NewDataView(aCx
, buffer
, byteOffset
, length
);
1255 #define CONSTRUCT_TYPED_ARRAY_TYPE(ExternalT, NativeT, Name) \
1256 case PullIntoDescriptor::Constructor::Name: \
1257 return JS_New##Name##ArrayWithBuffer(aCx, buffer, byteOffset, \
1261 JS_FOR_EACH_TYPED_ARRAY(CONSTRUCT_TYPED_ARRAY_TYPE
)
1263 #undef CONSTRUCT_TYPED_ARRAY_TYPE
1266 MOZ_ASSERT_UNREACHABLE("Unknown PullIntoDescriptor::Constructor");
1271 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-convert-pull-into-descriptor
1272 JSObject
* ReadableByteStreamControllerConvertPullIntoDescriptor(
1273 JSContext
* aCx
, PullIntoDescriptor
* pullIntoDescriptor
, ErrorResult
& aRv
) {
1274 // Step 1. Let bytesFilled be pullIntoDescriptor’s bytes filled.
1275 uint64_t bytesFilled
= pullIntoDescriptor
->BytesFilled();
1277 // Step 2. Let elementSize be pullIntoDescriptor’s element size.
1278 uint64_t elementSize
= pullIntoDescriptor
->ElementSize();
1280 // Step 3. Assert: bytesFilled ≤ pullIntoDescriptor’s byte length.
1281 MOZ_ASSERT(bytesFilled
<= pullIntoDescriptor
->ByteLength());
1283 // Step 4. Assert: bytesFilled mod elementSize is 0.
1284 MOZ_ASSERT(bytesFilled
% elementSize
== 0);
1286 // Step 5. Let buffer be ! TransferArrayBuffer(pullIntoDescriptor’s buffer).
1287 aRv
.MightThrowJSException();
1288 JS::Rooted
<JSObject
*> srcBuffer(aCx
, pullIntoDescriptor
->Buffer());
1289 JS::Rooted
<JSObject
*> buffer(aCx
, TransferArrayBuffer(aCx
, srcBuffer
));
1291 aRv
.StealExceptionFromJSContext(aCx
);
1295 // Step 6. Return ! Construct(pullIntoDescriptor’s view constructor,
1296 // « buffer, pullIntoDescriptor’s byte offset, bytesFilled ÷ elementSize »).
1297 JS::Rooted
<JSObject
*> res(
1298 aCx
, ConstructFromPullIntoConstructor(
1299 aCx
, pullIntoDescriptor
->ViewConstructor(), buffer
,
1300 pullIntoDescriptor
->ByteOffset(), bytesFilled
/ elementSize
));
1302 aRv
.StealExceptionFromJSContext(aCx
);
1308 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-in-closed-state
1310 static void ReadableByteStreamControllerRespondInClosedState(
1311 JSContext
* aCx
, ReadableByteStreamController
* aController
,
1312 RefPtr
<PullIntoDescriptor
>& aFirstDescriptor
, ErrorResult
& aRv
) {
1313 // Step 1. Assert: firstDescriptor ’s bytes filled is 0.
1314 MOZ_ASSERT(aFirstDescriptor
->BytesFilled() == 0);
1316 // Step 2. If firstDescriptor’s reader type is "none",
1317 // perform ! ReadableByteStreamControllerShiftPendingPullInto(controller).
1318 if (aFirstDescriptor
->GetReaderType() == ReaderType::None
) {
1319 RefPtr
<PullIntoDescriptor
> discarded
=
1320 ReadableByteStreamControllerShiftPendingPullInto(aController
);
1324 // Step 3. Let stream be controller.[[stream]].
1325 RefPtr
<ReadableStream
> stream
= aController
->Stream();
1327 // Step 4. If ! ReadableStreamHasBYOBReader(stream) is true,
1328 if (ReadableStreamHasBYOBReader(stream
)) {
1329 // Step 4.1. While ! ReadableStreamGetNumReadIntoRequests(stream) > 0,
1330 while (ReadableStreamGetNumReadIntoRequests(stream
) > 0) {
1331 // Step 4.1.1. Let pullIntoDescriptor be !
1332 // ReadableByteStreamControllerShiftPendingPullInto(controller).
1333 RefPtr
<PullIntoDescriptor
> pullIntoDescriptor
=
1334 ReadableByteStreamControllerShiftPendingPullInto(aController
);
1336 // Step 4.1.2. Perform !
1337 // ReadableByteStreamControllerCommitPullIntoDescriptor(stream,
1338 // pullIntoDescriptor).
1339 ReadableByteStreamControllerCommitPullIntoDescriptor(
1340 aCx
, stream
, pullIntoDescriptor
, aRv
);
1345 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-fill-head-pull-into-descriptor
1346 void ReadableByteStreamControllerFillHeadPullIntoDescriptor(
1347 ReadableByteStreamController
* aController
, size_t aSize
,
1348 PullIntoDescriptor
* aPullIntoDescriptor
) {
1349 // Step 1. Assert: either controller.[[pendingPullIntos]] is empty, or
1350 // controller.[[pendingPullIntos]][0] is pullIntoDescriptor.
1351 MOZ_ASSERT(aController
->PendingPullIntos().isEmpty() ||
1352 aController
->PendingPullIntos().getFirst() == aPullIntoDescriptor
);
1354 // Step 2. Assert: controller.[[byobRequest]] is null.
1355 MOZ_ASSERT(!aController
->GetByobRequest());
1357 // Step 3. Set pullIntoDescriptor’s bytes filled to bytes filled + size.
1358 aPullIntoDescriptor
->SetBytesFilled(aPullIntoDescriptor
->BytesFilled() +
1362 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-in-readable-state
1364 static void ReadableByteStreamControllerRespondInReadableState(
1365 JSContext
* aCx
, ReadableByteStreamController
* aController
,
1366 uint64_t aBytesWritten
, PullIntoDescriptor
* aPullIntoDescriptor
,
1368 // Step 1. Assert: pullIntoDescriptor’s bytes filled + bytesWritten ≤
1369 // pullIntoDescriptor’s byte length.
1370 MOZ_ASSERT(aPullIntoDescriptor
->BytesFilled() + aBytesWritten
<=
1371 aPullIntoDescriptor
->ByteLength());
1374 // !ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller,
1375 // bytesWritten, pullIntoDescriptor).
1376 ReadableByteStreamControllerFillHeadPullIntoDescriptor(
1377 aController
, aBytesWritten
, aPullIntoDescriptor
);
1379 // Step 3. If pullIntoDescriptor’s reader type is "none",
1380 if (aPullIntoDescriptor
->GetReaderType() == ReaderType::None
) {
1381 // Step 3.1. Perform ?
1382 // ReadableByteStreamControllerEnqueueDetachedPullIntoToQueue(controller,
1383 // pullIntoDescriptor).
1384 ReadableByteStreamControllerEnqueueDetachedPullIntoToQueue(
1385 aCx
, aController
, aPullIntoDescriptor
, aRv
);
1390 // Step 3.2. Perform !
1391 // ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller).
1392 ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(
1393 aCx
, aController
, aRv
);
1395 // Step 3.3. Return.
1399 // Step 4. If pullIntoDescriptor’s bytes filled < pullIntoDescriptor’s element
1401 if (aPullIntoDescriptor
->BytesFilled() < aPullIntoDescriptor
->ElementSize()) {
1406 // !ReadableByteStreamControllerShiftPendingPullInto(controller).
1407 RefPtr
<PullIntoDescriptor
> pullIntoDescriptor
=
1408 ReadableByteStreamControllerShiftPendingPullInto(aController
);
1409 (void)pullIntoDescriptor
;
1411 // Step 6. Let remainderSize be pullIntoDescriptor’s bytes filled mod
1412 // pullIntoDescriptor’s element size.
1413 size_t remainderSize
=
1414 aPullIntoDescriptor
->BytesFilled() % aPullIntoDescriptor
->ElementSize();
1416 // Step 7. If remainderSize > 0,
1417 if (remainderSize
> 0) {
1418 // Step 7.1. Let end be pullIntoDescriptor’s byte offset +
1419 // pullIntoDescriptor’s bytes filled.
1421 aPullIntoDescriptor
->ByteOffset() + aPullIntoDescriptor
->BytesFilled();
1423 // Step 7.2. Perform ?
1424 // ReadableByteStreamControllerEnqueueClonedChunkToQueue(controller,
1425 // pullIntoDescriptor’s buffer, end − remainderSize, remainderSize).
1426 JS::Rooted
<JSObject
*> pullIntoBuffer(aCx
, aPullIntoDescriptor
->Buffer());
1427 ReadableByteStreamControllerEnqueueClonedChunkToQueue(
1428 aCx
, aController
, pullIntoBuffer
, end
- remainderSize
, remainderSize
,
1435 // Step 8. Set pullIntoDescriptor’s bytes filled to pullIntoDescriptor’s bytes
1436 // filled − remainderSize.
1437 aPullIntoDescriptor
->SetBytesFilled(aPullIntoDescriptor
->BytesFilled() -
1441 // !ReadableByteStreamControllerCommitPullIntoDescriptor(controller.[[stream]],
1442 // pullIntoDescriptor).
1443 RefPtr
<ReadableStream
> stream(aController
->Stream());
1444 ReadableByteStreamControllerCommitPullIntoDescriptor(
1445 aCx
, stream
, aPullIntoDescriptor
, aRv
);
1451 // !ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller).
1452 ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(
1453 aCx
, aController
, aRv
);
1456 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-internal
1457 void ReadableByteStreamControllerRespondInternal(
1458 JSContext
* aCx
, ReadableByteStreamController
* aController
,
1459 uint64_t aBytesWritten
, ErrorResult
& aRv
) {
1461 RefPtr
<PullIntoDescriptor
> firstDescriptor
=
1462 aController
->PendingPullIntos().getFirst();
1465 JS::Rooted
<JSObject
*> buffer(aCx
, firstDescriptor
->Buffer());
1467 bool canTransferBuffer
= CanTransferArrayBuffer(aCx
, buffer
, aRv
);
1468 MOZ_ASSERT(!aRv
.Failed());
1469 MOZ_ASSERT(canTransferBuffer
);
1473 ReadableByteStreamControllerInvalidateBYOBRequest(aController
);
1476 auto state
= aController
->Stream()->State();
1479 if (state
== ReadableStream::ReaderState::Closed
) {
1481 MOZ_ASSERT(aBytesWritten
== 0);
1484 ReadableByteStreamControllerRespondInClosedState(aCx
, aController
,
1485 firstDescriptor
, aRv
);
1491 MOZ_ASSERT(state
== ReadableStream::ReaderState::Readable
);
1494 MOZ_ASSERT(aBytesWritten
> 0);
1497 ReadableByteStreamControllerRespondInReadableState(
1498 aCx
, aController
, aBytesWritten
, firstDescriptor
, aRv
);
1504 ReadableByteStreamControllerCallPullIfNeeded(aCx
, aController
, aRv
);
1507 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond
1508 void ReadableByteStreamControllerRespond(
1509 JSContext
* aCx
, ReadableByteStreamController
* aController
,
1510 uint64_t aBytesWritten
, ErrorResult
& aRv
) {
1512 MOZ_ASSERT(!aController
->PendingPullIntos().isEmpty());
1515 PullIntoDescriptor
* firstDescriptor
=
1516 aController
->PendingPullIntos().getFirst();
1519 auto state
= aController
->Stream()->State();
1522 if (state
== ReadableStream::ReaderState::Closed
) {
1524 if (aBytesWritten
!= 0) {
1525 aRv
.ThrowTypeError("bytesWritten not zero on closed stream");
1530 MOZ_ASSERT(state
== ReadableStream::ReaderState::Readable
);
1533 if (aBytesWritten
== 0) {
1534 aRv
.ThrowTypeError("bytesWritten 0");
1539 if (firstDescriptor
->BytesFilled() + aBytesWritten
>
1540 firstDescriptor
->ByteLength()) {
1541 aRv
.ThrowRangeError("bytesFilled + bytesWritten > byteLength");
1547 aRv
.MightThrowJSException();
1548 JS::Rooted
<JSObject
*> buffer(aCx
, firstDescriptor
->Buffer());
1549 JS::Rooted
<JSObject
*> transferredBuffer(aCx
,
1550 TransferArrayBuffer(aCx
, buffer
));
1551 if (!transferredBuffer
) {
1552 aRv
.StealExceptionFromJSContext(aCx
);
1555 firstDescriptor
->SetBuffer(transferredBuffer
);
1558 ReadableByteStreamControllerRespondInternal(aCx
, aController
, aBytesWritten
,
1562 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-with-new-view
1563 void ReadableByteStreamControllerRespondWithNewView(
1564 JSContext
* aCx
, ReadableByteStreamController
* aController
,
1565 JS::Handle
<JSObject
*> aView
, ErrorResult
& aRv
) {
1566 aRv
.MightThrowJSException();
1569 MOZ_ASSERT(!aController
->PendingPullIntos().isEmpty());
1572 bool isSharedMemory
;
1573 JS::Rooted
<JSObject
*> viewedArrayBuffer(
1574 aCx
, JS_GetArrayBufferViewBuffer(aCx
, aView
, &isSharedMemory
));
1575 if (!viewedArrayBuffer
) {
1576 aRv
.StealExceptionFromJSContext(aCx
);
1579 MOZ_ASSERT(!JS::IsDetachedArrayBufferObject(viewedArrayBuffer
));
1582 RefPtr
<PullIntoDescriptor
> firstDescriptor
=
1583 aController
->PendingPullIntos().getFirst();
1586 ReadableStream::ReaderState state
= aController
->Stream()->State();
1589 if (state
== ReadableStream::ReaderState::Closed
) {
1591 if (JS_GetArrayBufferViewByteLength(aView
) != 0) {
1592 aRv
.ThrowTypeError("View has non-zero length in closed stream");
1597 MOZ_ASSERT(state
== ReadableStream::ReaderState::Readable
);
1600 if (JS_GetArrayBufferViewByteLength(aView
) == 0) {
1601 aRv
.ThrowTypeError("View has zero length in readable stream");
1607 if (firstDescriptor
->ByteOffset() + firstDescriptor
->BytesFilled() !=
1608 JS_GetArrayBufferViewByteOffset(aView
)) {
1609 aRv
.ThrowRangeError("Invalid Offset");
1614 if (firstDescriptor
->BufferByteLength() !=
1615 JS::GetArrayBufferByteLength(viewedArrayBuffer
)) {
1616 aRv
.ThrowRangeError("Mismatched buffer byte lengths");
1621 if (firstDescriptor
->BytesFilled() + JS_GetArrayBufferViewByteLength(aView
) >
1622 firstDescriptor
->ByteLength()) {
1623 aRv
.ThrowRangeError("Too many bytes");
1627 // Step 10. Let viewByteLength be view.[[ByteLength]].
1628 size_t viewByteLength
= JS_GetArrayBufferViewByteLength(aView
);
1630 // Step 11. Set firstDescriptor’s buffer to ?
1631 // TransferArrayBuffer(view.[[ViewedArrayBuffer]]).
1632 JS::Rooted
<JSObject
*> transferedBuffer(
1633 aCx
, TransferArrayBuffer(aCx
, viewedArrayBuffer
));
1634 if (!transferedBuffer
) {
1635 aRv
.StealExceptionFromJSContext(aCx
);
1638 firstDescriptor
->SetBuffer(transferedBuffer
);
1640 // Step 12. Perform ? ReadableByteStreamControllerRespondInternal(controller,
1642 ReadableByteStreamControllerRespondInternal(aCx
, aController
, viewByteLength
,
1646 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-fill-pull-into-descriptor-from-queue
1647 bool ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(
1648 JSContext
* aCx
, ReadableByteStreamController
* aController
,
1649 PullIntoDescriptor
* aPullIntoDescriptor
, ErrorResult
& aRv
) {
1650 // Step 1. Let elementSize be pullIntoDescriptor.[[elementSize]].
1651 size_t elementSize
= aPullIntoDescriptor
->ElementSize();
1653 // Step 2. Let currentAlignedBytes be pullIntoDescriptor’s bytes filled −
1654 // (pullIntoDescriptor’s bytes filled mod elementSize).
1655 size_t currentAlignedBytes
=
1656 aPullIntoDescriptor
->BytesFilled() -
1657 (aPullIntoDescriptor
->BytesFilled() % elementSize
);
1659 // Step 3. Let maxBytesToCopy be min(controller.[[queueTotalSize]],
1660 // pullIntoDescriptor’s byte length − pullIntoDescriptor’s bytes filled).
1661 size_t maxBytesToCopy
=
1662 std::min(static_cast<size_t>(aController
->QueueTotalSize()),
1663 static_cast<size_t>((aPullIntoDescriptor
->ByteLength() -
1664 aPullIntoDescriptor
->BytesFilled())));
1666 // Step 4. Let maxBytesFilled be pullIntoDescriptor’s bytes filled +
1668 size_t maxBytesFilled
= aPullIntoDescriptor
->BytesFilled() + maxBytesToCopy
;
1670 // Step 5. Let maxAlignedBytes be maxBytesFilled − (maxBytesFilled mod
1672 size_t maxAlignedBytes
= maxBytesFilled
- (maxBytesFilled
% elementSize
);
1674 // Step 6. Let totalBytesToCopyRemaining be maxBytesToCopy.
1675 size_t totalBytesToCopyRemaining
= maxBytesToCopy
;
1677 // Step 7. Let ready be false.
1680 // Step 8. If maxAlignedBytes > currentAlignedBytes,
1681 if (maxAlignedBytes
> currentAlignedBytes
) {
1682 // Step 8.1. Set totalBytesToCopyRemaining to maxAlignedBytes −
1683 // pullIntoDescriptor’s bytes filled.
1684 totalBytesToCopyRemaining
=
1685 maxAlignedBytes
- aPullIntoDescriptor
->BytesFilled();
1686 // Step 8.2. Set ready to true.
1690 // Step 9. Let queue be controller.[[queue]].
1691 LinkedList
<RefPtr
<ReadableByteStreamQueueEntry
>>& queue
=
1692 aController
->Queue();
1694 // Step 10. While totalBytesToCopyRemaining > 0,
1695 while (totalBytesToCopyRemaining
> 0) {
1696 // Step 10.1 Let headOfQueue be queue[0].
1697 ReadableByteStreamQueueEntry
* headOfQueue
= queue
.getFirst();
1699 // Step 10.2. Let bytesToCopy be min(totalBytesToCopyRemaining,
1700 // headOfQueue’s byte length).
1701 size_t bytesToCopy
=
1702 std::min(totalBytesToCopyRemaining
, headOfQueue
->ByteLength());
1704 // Step 10.3. Let destStart be pullIntoDescriptor’s byte offset +
1705 // pullIntoDescriptor’s bytes filled.
1707 aPullIntoDescriptor
->ByteOffset() + aPullIntoDescriptor
->BytesFilled();
1709 // Step 10.4. Perform !CopyDataBlockBytes(pullIntoDescriptor’s
1710 // buffer.[[ArrayBufferData]], destStart, headOfQueue’s
1711 // buffer.[[ArrayBufferData]], headOfQueue’s byte offset,
1713 JS::Rooted
<JSObject
*> descriptorBuffer(aCx
, aPullIntoDescriptor
->Buffer());
1714 JS::Rooted
<JSObject
*> queueBuffer(aCx
, headOfQueue
->Buffer());
1715 if (!JS::ArrayBufferCopyData(aCx
, descriptorBuffer
, destStart
, queueBuffer
,
1716 headOfQueue
->ByteOffset(), bytesToCopy
)) {
1717 aRv
.StealExceptionFromJSContext(aCx
);
1721 // Step 10.5. If headOfQueue’s byte length is bytesToCopy,
1722 if (headOfQueue
->ByteLength() == bytesToCopy
) {
1723 // Step 10.5.1. Remove queue[0].
1726 // Step 10.6. Otherwise,
1728 // Step 10.6.1 Set headOfQueue’s byte offset to
1729 // headOfQueue’s byte offset + bytesToCopy.
1730 headOfQueue
->SetByteOffset(headOfQueue
->ByteOffset() + bytesToCopy
);
1731 // Step 10.6.2 Set headOfQueue’s byte length to
1732 // headOfQueue’s byte length − bytesToCopy.
1733 headOfQueue
->SetByteLength(headOfQueue
->ByteLength() - bytesToCopy
);
1736 // Step 10.7. Set controller.[[queueTotalSize]] to
1737 // controller.[[queueTotalSize]] − bytesToCopy.
1738 aController
->SetQueueTotalSize(aController
->QueueTotalSize() -
1739 (double)bytesToCopy
);
1741 // Step 10.8, Perform
1742 // !ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller,
1743 // bytesToCopy, pullIntoDescriptor).
1744 ReadableByteStreamControllerFillHeadPullIntoDescriptor(
1745 aController
, bytesToCopy
, aPullIntoDescriptor
);
1747 // Step 10.9. Set totalBytesToCopyRemaining to totalBytesToCopyRemaining −
1749 totalBytesToCopyRemaining
= totalBytesToCopyRemaining
- bytesToCopy
;
1752 // Step 11. If ready is false,
1754 // Step 11.1. Assert: controller.[[queueTotalSize]] is 0.
1755 MOZ_ASSERT(aController
->QueueTotalSize() == 0);
1757 // Step 11.2. Assert: pullIntoDescriptor’s bytes filled > 0.
1758 MOZ_ASSERT(aPullIntoDescriptor
->BytesFilled() > 0);
1760 // Step 11.3. Assert: pullIntoDescriptor’s bytes filled <
1761 // pullIntoDescriptor’s
1763 MOZ_ASSERT(aPullIntoDescriptor
->BytesFilled() <
1764 aPullIntoDescriptor
->ElementSize());
1767 // Step 12. Return ready.
1771 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-pull-into
1772 void ReadableByteStreamControllerPullInto(
1773 JSContext
* aCx
, ReadableByteStreamController
* aController
,
1774 JS::Handle
<JSObject
*> aView
, ReadIntoRequest
* aReadIntoRequest
,
1776 aRv
.MightThrowJSException();
1778 // Step 1. Let stream be controller.[[stream]].
1779 ReadableStream
* stream
= aController
->Stream();
1781 // Step 2. Let elementSize be 1.
1782 size_t elementSize
= 1;
1784 // Step 3. Let ctor be %DataView%.
1785 PullIntoDescriptor::Constructor ctor
=
1786 PullIntoDescriptor::Constructor::DataView
;
1788 // Step 4. If view has a [[TypedArrayName]] internal slot (i.e., it is not a
1790 if (JS_IsTypedArrayObject(aView
)) {
1791 // Step 4.1. Set elementSize to the element size specified in the typed
1792 // array constructors table for view.[[TypedArrayName]].
1793 JS::Scalar::Type type
= JS_GetArrayBufferViewType(aView
);
1794 elementSize
= JS::Scalar::byteSize(type
);
1796 // Step 4.2 Set ctor to the constructor specified in the typed array
1797 // constructors table for view.[[TypedArrayName]].
1798 ctor
= PullIntoDescriptor::constructorFromScalar(type
);
1801 // Step 5. Let byteOffset be view.[[ByteOffset]].
1802 size_t byteOffset
= JS_GetArrayBufferViewByteOffset(aView
);
1804 // Step 6. Let byteLength be view.[[ByteLength]].
1805 size_t byteLength
= JS_GetArrayBufferViewByteLength(aView
);
1807 // Step 7. Let bufferResult be
1808 // TransferArrayBuffer(view.[[ViewedArrayBuffer]]).
1810 JS::Rooted
<JSObject
*> viewedArrayBuffer(
1811 aCx
, JS_GetArrayBufferViewBuffer(aCx
, aView
, &isShared
));
1812 if (!viewedArrayBuffer
) {
1813 aRv
.StealExceptionFromJSContext(aCx
);
1816 JS::Rooted
<JSObject
*> bufferResult(
1817 aCx
, TransferArrayBuffer(aCx
, viewedArrayBuffer
));
1819 // Step 8. If bufferResult is an abrupt completion,
1820 if (!bufferResult
) {
1821 JS::Rooted
<JS::Value
> pendingException(aCx
);
1822 if (!JS_GetPendingException(aCx
, &pendingException
)) {
1823 // This means an un-catchable exception. Use StealExceptionFromJSContext
1824 // to setup aRv properly.
1825 aRv
.StealExceptionFromJSContext(aCx
);
1829 // It's not expliclitly stated, but I assume the intention here is that
1830 // we perform a normal completion here; we also need to clear the
1831 // exception state anyhow to succesfully run ErrorSteps.
1832 JS_ClearPendingException(aCx
);
1834 // Step 8.1. Perform readIntoRequest’s error steps, given
1835 // bufferResult.[[Value]].
1836 aReadIntoRequest
->ErrorSteps(aCx
, pendingException
, aRv
);
1838 // Step 8.2. Return.
1842 // Step 9. Let buffer be bufferResult.[[Value]].
1843 JS::Rooted
<JSObject
*> buffer(aCx
, bufferResult
);
1845 // Step 10. Let pullIntoDescriptor be a new pull-into descriptor with
1847 // buffer byte length: buffer.[[ArrayBufferByteLength]],
1848 // byte offset: byteOffset,
1849 // byte length: byteLength,
1851 // element size: elementSize,
1852 // view constructor: ctor,
1853 // and reader type: "byob".
1854 RefPtr
<PullIntoDescriptor
> pullIntoDescriptor
= new PullIntoDescriptor(
1855 buffer
, JS::GetArrayBufferByteLength(buffer
), byteOffset
, byteLength
, 0,
1856 elementSize
, ctor
, ReaderType::BYOB
);
1858 // Step 11. If controller.[[pendingPullIntos]] is not empty,
1859 if (!aController
->PendingPullIntos().isEmpty()) {
1860 // Step 11.1. Append pullIntoDescriptor to controller.[[pendingPullIntos]].
1861 aController
->PendingPullIntos().insertBack(pullIntoDescriptor
);
1863 // Step 11.2. Perform !ReadableStreamAddReadIntoRequest(stream,
1864 // readIntoRequest).
1865 ReadableStreamAddReadIntoRequest(stream
, aReadIntoRequest
);
1867 // Step 11.3. Return.
1871 // Step 12. If stream.[[state]] is "closed",
1872 if (stream
->State() == ReadableStream::ReaderState::Closed
) {
1873 // Step 12.1. Let emptyView be !Construct(ctor, « pullIntoDescriptor’s
1874 // buffer, pullIntoDescriptor’s byte offset, 0 »).
1875 JS::Rooted
<JSObject
*> pullIntoBuffer(aCx
, pullIntoDescriptor
->Buffer());
1876 JS::Rooted
<JSObject
*> emptyView(
1878 ConstructFromPullIntoConstructor(aCx
, ctor
, pullIntoBuffer
,
1879 pullIntoDescriptor
->ByteOffset(), 0));
1881 aRv
.StealExceptionFromJSContext(aCx
);
1885 // Step 12.2. Perform readIntoRequest’s close steps, given emptyView.
1886 JS::Rooted
<JS::Value
> emptyViewValue(aCx
, JS::ObjectValue(*emptyView
));
1887 aReadIntoRequest
->CloseSteps(aCx
, emptyViewValue
, aRv
);
1889 // Step 12.3. Return.
1893 // Step 13,. If controller.[[queueTotalSize]] > 0,
1894 if (aController
->QueueTotalSize() > 0) {
1896 // !ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller,
1897 // pullIntoDescriptor) is true,
1898 bool ready
= ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(
1899 aCx
, aController
, pullIntoDescriptor
, aRv
);
1904 // Step 13.1.1 Let filledView be
1905 // !ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor).
1906 JS::Rooted
<JSObject
*> filledView(
1907 aCx
, ReadableByteStreamControllerConvertPullIntoDescriptor(
1908 aCx
, pullIntoDescriptor
, aRv
));
1912 // Step 13.1.2. Perform
1913 // !ReadableByteStreamControllerHandleQueueDrain(controller).
1914 ReadableByteStreamControllerHandleQueueDrain(aCx
, aController
, aRv
);
1918 // Step 13.1.3. Perform readIntoRequest’s chunk steps, given filledView.
1919 JS::Rooted
<JS::Value
> filledViewValue(aCx
, JS::ObjectValue(*filledView
));
1920 aReadIntoRequest
->ChunkSteps(aCx
, filledViewValue
, aRv
);
1921 // Step 13.1.4. Return.
1925 // Step 13.2 If controller.[[closeRequested]] is true,
1926 if (aController
->CloseRequested()) {
1927 // Step 13.2.1. Let e be a TypeError exception.
1928 ErrorResult typeError
;
1929 typeError
.ThrowTypeError("Close Requested True during Pull Into");
1931 JS::Rooted
<JS::Value
> e(aCx
);
1932 MOZ_RELEASE_ASSERT(ToJSValue(aCx
, std::move(typeError
), &e
));
1934 // Step 13.2.2. Perform !ReadableByteStreamControllerError(controller, e).
1935 ReadableByteStreamControllerError(aController
, e
, aRv
);
1940 // Step 13.2.3. Perform readIntoRequest’s error steps, given e.
1941 aReadIntoRequest
->ErrorSteps(aCx
, e
, aRv
);
1943 // Step 13.2.4. Return.
1948 // Step 14. Append pullIntoDescriptor to controller.[[pendingPullIntos]].
1949 aController
->PendingPullIntos().insertBack(pullIntoDescriptor
);
1951 // Step 15. Perform !ReadableStreamAddReadIntoRequest(stream,
1952 // readIntoRequest).
1953 ReadableStreamAddReadIntoRequest(stream
, aReadIntoRequest
);
1956 // !ReadableByteStreamControllerCallPullIfNeeded(controller).
1957 ReadableByteStreamControllerCallPullIfNeeded(aCx
, aController
, aRv
);
1960 // https://streams.spec.whatwg.org/#set-up-readable-byte-stream-controller
1961 void SetUpReadableByteStreamController(
1962 JSContext
* aCx
, ReadableStream
* aStream
,
1963 ReadableByteStreamController
* aController
,
1964 UnderlyingSourceAlgorithmsBase
* aAlgorithms
, double aHighWaterMark
,
1965 Maybe
<uint64_t> aAutoAllocateChunkSize
, ErrorResult
& aRv
) {
1966 // Step 1. Assert: stream.[[controller]] is undefined.
1967 MOZ_ASSERT(!aStream
->Controller());
1969 // Step 2. If autoAllocateChunkSize is not undefined,
1970 // Step 2.1. Assert: ! IsInteger(autoAllocateChunkSize) is true. Implicit
1971 // Step 2.2. Assert: autoAllocateChunkSize is positive. (Implicit by
1974 // Step 3. Set controller.[[stream]] to stream.
1975 aController
->SetStream(aStream
);
1977 // Step 4. Set controller.[[pullAgain]] and controller.[[pulling]] to false.
1978 aController
->SetPullAgain(false);
1979 aController
->SetPulling(false);
1981 // Step 5. Set controller.[[byobRequest]] to null.
1982 aController
->SetByobRequest(nullptr);
1984 // Step 6. Perform !ResetQueue(controller).
1985 ResetQueue(aController
);
1987 // Step 7. Set controller.[[closeRequested]] and controller.[[started]] to
1989 aController
->SetCloseRequested(false);
1990 aController
->SetStarted(false);
1992 // Step 8. Set controller.[[strategyHWM]] to highWaterMark.
1993 aController
->SetStrategyHWM(aHighWaterMark
);
1995 // Step 9. Set controller.[[pullAlgorithm]] to pullAlgorithm.
1996 // Step 10. Set controller.[[cancelAlgorithm]] to cancelAlgorithm.
1997 aController
->SetAlgorithms(*aAlgorithms
);
1999 // Step 11. Set controller.[[autoAllocateChunkSize]] to autoAllocateChunkSize.
2000 aController
->SetAutoAllocateChunkSize(aAutoAllocateChunkSize
);
2002 // Step 12. Set controller.[[pendingPullIntos]] to a new empty list.
2003 aController
->PendingPullIntos().clear();
2005 // Step 13. Set stream.[[controller]] to controller.
2006 aStream
->SetController(*aController
);
2008 // Step 14. Let startResult be the result of performing startAlgorithm.
2009 JS::Rooted
<JS::Value
> startResult(aCx
, JS::UndefinedValue());
2010 RefPtr
<ReadableStreamController
> controller
= aController
;
2011 aAlgorithms
->StartCallback(aCx
, *controller
, &startResult
, aRv
);
2016 // Let startPromise be a promise resolved with startResult.
2017 RefPtr
<Promise
> startPromise
=
2018 Promise::CreateInfallible(aStream
->GetParentObject());
2019 startPromise
->MaybeResolve(startResult
);
2022 startPromise
->AddCallbacksWithCycleCollectedArgs(
2023 [](JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
, ErrorResult
& aRv
,
2024 ReadableByteStreamController
* aController
)
2025 MOZ_CAN_RUN_SCRIPT_BOUNDARY
{
2026 MOZ_ASSERT(aController
);
2029 aController
->SetStarted(true);
2032 aController
->SetPulling(false);
2035 aController
->SetPullAgain(false);
2038 ReadableByteStreamControllerCallPullIfNeeded(
2039 aCx
, MOZ_KnownLive(aController
), aRv
);
2041 [](JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
, ErrorResult
& aRv
,
2042 ReadableByteStreamController
* aController
) {
2044 ReadableByteStreamControllerError(aController
, aValue
, aRv
);
2046 RefPtr(aController
));
2049 // https://streams.spec.whatwg.org/#set-up-readable-byte-stream-controller-from-underlying-source
2050 void SetUpReadableByteStreamControllerFromUnderlyingSource(
2051 JSContext
* aCx
, ReadableStream
* aStream
,
2052 JS::Handle
<JSObject
*> aUnderlyingSource
,
2053 UnderlyingSource
& aUnderlyingSourceDict
, double aHighWaterMark
,
2055 // Step 1. Let controller be a new ReadableByteStreamController.
2057 MakeRefPtr
<ReadableByteStreamController
>(aStream
->GetParentObject());
2060 auto algorithms
= MakeRefPtr
<UnderlyingSourceAlgorithms
>(
2061 aStream
->GetParentObject(), aUnderlyingSource
, aUnderlyingSourceDict
);
2063 // Step 8. Let autoAllocateChunkSize be
2064 // underlyingSourceDict["autoAllocateChunkSize"], if it exists, or undefined
2066 Maybe
<uint64_t> autoAllocateChunkSize
= mozilla::Nothing();
2067 if (aUnderlyingSourceDict
.mAutoAllocateChunkSize
.WasPassed()) {
2068 uint64_t value
= aUnderlyingSourceDict
.mAutoAllocateChunkSize
.Value();
2069 // Step 9. If autoAllocateChunkSize is 0, then throw a TypeError
2072 aRv
.ThrowTypeError("autoAllocateChunkSize can not be zero.");
2075 autoAllocateChunkSize
= mozilla::Some(value
);
2078 // Step 10. Perform ? SetUpReadableByteStreamController(stream, controller,
2079 // startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark,
2080 // autoAllocateChunkSize).
2081 SetUpReadableByteStreamController(aCx
, aStream
, controller
, algorithms
,
2082 aHighWaterMark
, autoAllocateChunkSize
, aRv
);
2085 } // namespace streams_abstract
2087 } // namespace mozilla::dom