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/BodyStream.h"
8 #include "mozilla/dom/ByteStreamHelpers.h"
9 #include "mozilla/dom/ReadableByteStreamController.h"
10 #include "js/ArrayBuffer.h"
11 #include "js/RootingAPI.h"
12 #include "js/experimental/TypedData.h"
13 #include "mozilla/ErrorResult.h"
15 namespace mozilla::dom
{
17 // https://streams.spec.whatwg.org/#transfer-array-buffer
18 // As some parts of the specifcation want to use the abrupt completion value,
19 // this function may leave a pending exception if it returns nullptr.
20 JSObject
* TransferArrayBuffer(JSContext
* aCx
, JS::Handle
<JSObject
*> aObject
) {
21 MOZ_ASSERT(JS::IsArrayBufferObject(aObject
));
24 MOZ_ASSERT(!JS::IsDetachedArrayBufferObject(aObject
));
27 size_t bufferLength
= JS::GetArrayBufferByteLength(aObject
);
30 void* bufferData
= JS::StealArrayBufferContents(aCx
, aObject
);
33 if (!JS::DetachArrayBuffer(aCx
, aObject
)) {
38 return JS::NewArrayBufferWithContents(aCx
, bufferLength
, bufferData
);
41 // https://streams.spec.whatwg.org/#can-transfer-array-buffer
42 bool CanTransferArrayBuffer(JSContext
* aCx
, JS::Handle
<JSObject
*> aObject
,
44 // Step 1. Assert: Type(O) is Object. (Implicit in types)
45 // Step 2. Assert: O has an [[ArrayBufferData]] internal slot.
46 MOZ_ASSERT(JS::IsArrayBufferObject(aObject
));
48 // Step 3. If ! IsDetachedBuffer(O) is true, return false.
49 if (JS::IsDetachedArrayBufferObject(aObject
)) {
53 // Step 4. If SameValue(O.[[ArrayBufferDetachKey]], undefined) is false,
55 // Step 5. Return true.
56 // Note: WASM memories are the only buffers that would qualify
57 // as having an undefined [[ArrayBufferDetachKey]],
58 bool hasDefinedArrayBufferDetachKey
= false;
59 if (!JS::HasDefinedArrayBufferDetachKey(aCx
, aObject
,
60 &hasDefinedArrayBufferDetachKey
)) {
61 aRv
.StealExceptionFromJSContext(aCx
);
64 return !hasDefinedArrayBufferDetachKey
;
67 // https://streams.spec.whatwg.org/#abstract-opdef-cloneasuint8array
68 JSObject
* CloneAsUint8Array(JSContext
* aCx
, JS::Handle
<JSObject
*> aObject
) {
69 // Step 1. Assert: Type(O) is Object. Implicit.
70 // Step 2. Assert: O has an [[ViewedArrayBuffer]] internal slot.
71 MOZ_ASSERT(JS_IsArrayBufferViewObject(aObject
));
73 // Step 3. Assert: !IsDetachedBuffer(O.[[ViewedArrayBuffer]]) is false.
75 JS::Rooted
<JSObject
*> viewedArrayBuffer(
76 aCx
, JS_GetArrayBufferViewBuffer(aCx
, aObject
, &isShared
));
77 if (!viewedArrayBuffer
) {
80 MOZ_ASSERT(!JS::IsDetachedArrayBufferObject(viewedArrayBuffer
));
82 // Step 4. Let buffer be ?CloneArrayBuffer(O.[[ViewedArrayBuffer]],
83 // O.[[ByteOffset]], O.[[ByteLength]], %ArrayBuffer%).
84 size_t byteOffset
= JS_GetTypedArrayByteOffset(aObject
);
85 size_t byteLength
= JS_GetTypedArrayByteLength(aObject
);
86 JS::Rooted
<JSObject
*> buffer(
88 JS::ArrayBufferClone(aCx
, viewedArrayBuffer
, byteOffset
, byteLength
));
93 // Step 5. Let array be ! Construct(%Uint8Array%, « buffer »).
94 JS::Rooted
<JSObject
*> array(
95 aCx
, JS_NewUint8ArrayWithBuffer(aCx
, buffer
, 0,
96 static_cast<int64_t>(byteLength
)));
101 // Step 6. Return array.
105 class BodyStreamUnderlyingSourceAlgorithms final
106 : public UnderlyingSourceAlgorithmsBase
{
108 NS_DECL_ISUPPORTS_INHERITED
109 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BodyStreamUnderlyingSourceAlgorithms
,
110 UnderlyingSourceAlgorithmsBase
)
112 explicit BodyStreamUnderlyingSourceAlgorithms(
113 BodyStreamHolder
* underlyingSource
)
114 : mUnderlyingSource(underlyingSource
) {}
116 MOZ_CAN_RUN_SCRIPT
void StartCallback(JSContext
* aCx
,
117 ReadableStreamController
& aController
,
118 JS::MutableHandle
<JS::Value
> aRetVal
,
119 ErrorResult
& aRv
) override
{
120 aRetVal
.setUndefined();
123 MOZ_CAN_RUN_SCRIPT already_AddRefed
<Promise
> PullCallback(
124 JSContext
* aCx
, ReadableStreamController
& aController
,
125 ErrorResult
& aRv
) override
{
126 RefPtr
<BodyStream
> bodyStream
= mUnderlyingSource
->GetBodyStream();
127 return bodyStream
->PullCallback(aCx
, aController
, aRv
);
130 MOZ_CAN_RUN_SCRIPT already_AddRefed
<Promise
> CancelCallback(
131 JSContext
* aCx
, const Optional
<JS::Handle
<JS::Value
>>& aReason
,
132 ErrorResult
& aRv
) override
{
133 RefPtr
<BodyStream
> bodyStream
= mUnderlyingSource
->GetBodyStream();
134 return bodyStream
->CancelCallback(aCx
, aReason
, aRv
);
137 void ErrorCallback() override
{
138 RefPtr
<BodyStream
> bodyStream
= mUnderlyingSource
->GetBodyStream();
139 bodyStream
->ErrorCallback();
143 ~BodyStreamUnderlyingSourceAlgorithms() override
= default;
146 RefPtr
<BodyStreamHolder
> mUnderlyingSource
;
149 NS_IMPL_CYCLE_COLLECTION_INHERITED(BodyStreamUnderlyingSourceAlgorithms
,
150 UnderlyingSourceAlgorithmsBase
,
152 NS_IMPL_ADDREF_INHERITED(BodyStreamUnderlyingSourceAlgorithms
,
153 UnderlyingSourceAlgorithmsBase
)
154 NS_IMPL_RELEASE_INHERITED(BodyStreamUnderlyingSourceAlgorithms
,
155 UnderlyingSourceAlgorithmsBase
)
156 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BodyStreamUnderlyingSourceAlgorithms
)
157 NS_INTERFACE_MAP_END_INHERITING(UnderlyingSourceAlgorithmsBase
)
159 // This is gently modelled on the pre-existing
160 // SetUpExternalReadableByteStreamController, but specialized to the
161 // BodyStreamUnderlyingSource model vs. the External streams of the JS
164 // https://streams.spec.whatwg.org/#set-up-readable-byte-stream-controller-from-underlying-source
165 void SetUpReadableByteStreamControllerFromBodyStreamUnderlyingSource(
166 JSContext
* aCx
, ReadableStream
* aStream
,
167 BodyStreamHolder
* aUnderlyingSource
, ErrorResult
& aRv
) {
170 MakeRefPtr
<ReadableByteStreamController
>(aStream
->GetParentObject());
174 MakeRefPtr
<BodyStreamUnderlyingSourceAlgorithms
>(aUnderlyingSource
);
177 Maybe
<uint64_t> autoAllocateChunkSize
= mozilla::Nothing();
180 // Not Specified: Native underlying sources always use 0.0 high water mark.
181 double highWaterMark
= 0.0;
184 SetUpReadableByteStreamController(aCx
, aStream
, controller
, algorithms
,
185 highWaterMark
, autoAllocateChunkSize
, aRv
);
188 } // namespace mozilla::dom