forked from mirrors/gecko-dev
Bug 1659025 - Implement [Transferable] for ReadableStream r=smaug,sfink
Differential Revision: https://phabricator.services.mozilla.com/D139525
This commit is contained in:
parent
ff14b28782
commit
2b7f799d55
32 changed files with 1550 additions and 214 deletions
|
|
@ -46,12 +46,18 @@
|
||||||
#include "mozilla/dom/MessagePortBinding.h"
|
#include "mozilla/dom/MessagePortBinding.h"
|
||||||
#include "mozilla/dom/OffscreenCanvas.h"
|
#include "mozilla/dom/OffscreenCanvas.h"
|
||||||
#include "mozilla/dom/OffscreenCanvasBinding.h"
|
#include "mozilla/dom/OffscreenCanvasBinding.h"
|
||||||
|
#include "mozilla/dom/ReadableStream.h"
|
||||||
|
#include "mozilla/dom/ReadableStreamBinding.h"
|
||||||
#include "mozilla/dom/ScriptSettings.h"
|
#include "mozilla/dom/ScriptSettings.h"
|
||||||
#include "mozilla/dom/StructuredCloneBlob.h"
|
#include "mozilla/dom/StructuredCloneBlob.h"
|
||||||
#include "mozilla/dom/StructuredCloneHolderBinding.h"
|
#include "mozilla/dom/StructuredCloneHolderBinding.h"
|
||||||
#include "mozilla/dom/StructuredCloneTags.h"
|
#include "mozilla/dom/StructuredCloneTags.h"
|
||||||
#include "mozilla/dom/ToJSValue.h"
|
#include "mozilla/dom/ToJSValue.h"
|
||||||
|
#include "mozilla/dom/TransformStream.h"
|
||||||
|
#include "mozilla/dom/TransformStreamBinding.h"
|
||||||
#include "mozilla/dom/WebIDLSerializable.h"
|
#include "mozilla/dom/WebIDLSerializable.h"
|
||||||
|
#include "mozilla/dom/WritableStream.h"
|
||||||
|
#include "mozilla/dom/WritableStreamBinding.h"
|
||||||
#include "mozilla/dom/WorkerCommon.h"
|
#include "mozilla/dom/WorkerCommon.h"
|
||||||
#include "mozilla/dom/WorkerPrivate.h"
|
#include "mozilla/dom/WorkerPrivate.h"
|
||||||
#include "mozilla/fallible.h"
|
#include "mozilla/fallible.h"
|
||||||
|
|
@ -1115,7 +1121,26 @@ bool StructuredCloneHolder::CustomWriteHandler(
|
||||||
return WriteFullySerializableObjects(aCx, aWriter, aObj);
|
return WriteFullySerializableObjects(aCx, aWriter, aObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StructuredCloneHolder::CustomReadTransferHandler(
|
already_AddRefed<MessagePort> StructuredCloneHolder::ReceiveMessagePort(
|
||||||
|
uint64_t aIndex) {
|
||||||
|
if (NS_WARN_IF(aIndex >= mPortIdentifiers.Length())) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
UniqueMessagePortId portId(mPortIdentifiers[aIndex]);
|
||||||
|
|
||||||
|
ErrorResult rv;
|
||||||
|
RefPtr<MessagePort> port = MessagePort::Create(mGlobal, portId, rv);
|
||||||
|
if (NS_WARN_IF(rv.Failed())) {
|
||||||
|
rv.SuppressException();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return port.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
|
||||||
|
MOZ_CAN_RUN_SCRIPT_BOUNDARY bool
|
||||||
|
StructuredCloneHolder::CustomReadTransferHandler(
|
||||||
JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag,
|
JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag,
|
||||||
void* aContent, uint64_t aExtraData,
|
void* aContent, uint64_t aExtraData,
|
||||||
JS::MutableHandleObject aReturnObject) {
|
JS::MutableHandleObject aReturnObject) {
|
||||||
|
|
@ -1127,16 +1152,10 @@ bool StructuredCloneHolder::CustomReadTransferHandler(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
MOZ_ASSERT(aExtraData < mPortIdentifiers.Length());
|
RefPtr<MessagePort> port = ReceiveMessagePort(aExtraData);
|
||||||
UniqueMessagePortId portIdentifier(mPortIdentifiers[aExtraData]);
|
if (!port) {
|
||||||
|
|
||||||
ErrorResult rv;
|
|
||||||
RefPtr<MessagePort> port = MessagePort::Create(mGlobal, portIdentifier, rv);
|
|
||||||
if (NS_WARN_IF(rv.Failed())) {
|
|
||||||
rv.SuppressException();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mTransferredPorts.AppendElement(port);
|
mTransferredPorts.AppendElement(port);
|
||||||
|
|
||||||
JS::Rooted<JS::Value> value(aCx);
|
JS::Rooted<JS::Value> value(aCx);
|
||||||
|
|
@ -1186,10 +1205,56 @@ bool StructuredCloneHolder::CustomReadTransferHandler(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (aTag == SCTAG_DOM_READABLESTREAM) {
|
||||||
|
#ifdef FUZZING
|
||||||
|
if (aExtraData >= mPortIdentifiers.Length()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
RefPtr<MessagePort> port = ReceiveMessagePort(aExtraData);
|
||||||
|
if (!port) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
nsCOMPtr<nsIGlobalObject> global = mGlobal;
|
||||||
|
return ReadableStream::ReceiveTransfer(aCx, global, *port, aReturnObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aTag == SCTAG_DOM_WRITABLESTREAM) {
|
||||||
|
#ifdef FUZZING
|
||||||
|
if (aExtraData >= mPortIdentifiers.Length()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
RefPtr<MessagePort> port = ReceiveMessagePort(aExtraData);
|
||||||
|
if (!port) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
nsCOMPtr<nsIGlobalObject> global = mGlobal;
|
||||||
|
return WritableStream::ReceiveTransfer(aCx, global, *port, aReturnObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aTag == SCTAG_DOM_TRANSFORMSTREAM) {
|
||||||
|
#ifdef FUZZING
|
||||||
|
if (aExtraData + 1 >= mPortIdentifiers.Length()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
RefPtr<MessagePort> port1 = ReceiveMessagePort(aExtraData);
|
||||||
|
RefPtr<MessagePort> port2 = ReceiveMessagePort(aExtraData + 1);
|
||||||
|
if (!port1 || !port2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
nsCOMPtr<nsIGlobalObject> global = mGlobal;
|
||||||
|
return TransformStream::ReceiveTransfer(aCx, global, *port1, *port2,
|
||||||
|
aReturnObject);
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StructuredCloneHolder::CustomWriteTransferHandler(
|
// TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
|
||||||
|
MOZ_CAN_RUN_SCRIPT_BOUNDARY bool
|
||||||
|
StructuredCloneHolder::CustomWriteTransferHandler(
|
||||||
JSContext* aCx, JS::Handle<JSObject*> aObj, uint32_t* aTag,
|
JSContext* aCx, JS::Handle<JSObject*> aObj, uint32_t* aTag,
|
||||||
JS::TransferableOwnership* aOwnership, void** aContent,
|
JS::TransferableOwnership* aOwnership, void** aContent,
|
||||||
uint64_t* aExtraData) {
|
uint64_t* aExtraData) {
|
||||||
|
|
@ -1263,6 +1328,68 @@ bool StructuredCloneHolder::CustomWriteTransferHandler(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
RefPtr<ReadableStream> stream;
|
||||||
|
rv = UNWRAP_OBJECT(ReadableStream, &obj, stream);
|
||||||
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
MOZ_ASSERT(stream);
|
||||||
|
|
||||||
|
*aTag = SCTAG_DOM_READABLESTREAM;
|
||||||
|
*aOwnership = JS::SCTAG_TMO_CUSTOM;
|
||||||
|
*aContent = nullptr;
|
||||||
|
|
||||||
|
UniqueMessagePortId id;
|
||||||
|
if (!stream->Transfer(aCx, id)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*aExtraData = mPortIdentifiers.Length();
|
||||||
|
mPortIdentifiers.AppendElement(id.release());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
RefPtr<WritableStream> stream;
|
||||||
|
rv = UNWRAP_OBJECT(WritableStream, &obj, stream);
|
||||||
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
MOZ_ASSERT(stream);
|
||||||
|
|
||||||
|
*aTag = SCTAG_DOM_WRITABLESTREAM;
|
||||||
|
*aOwnership = JS::SCTAG_TMO_CUSTOM;
|
||||||
|
*aContent = nullptr;
|
||||||
|
|
||||||
|
UniqueMessagePortId id;
|
||||||
|
if (!stream->Transfer(aCx, id)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*aExtraData = mPortIdentifiers.Length();
|
||||||
|
mPortIdentifiers.AppendElement(id.release());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
RefPtr<TransformStream> stream;
|
||||||
|
rv = UNWRAP_OBJECT(TransformStream, &obj, stream);
|
||||||
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
MOZ_ASSERT(stream);
|
||||||
|
|
||||||
|
*aTag = SCTAG_DOM_TRANSFORMSTREAM;
|
||||||
|
*aOwnership = JS::SCTAG_TMO_CUSTOM;
|
||||||
|
*aContent = nullptr;
|
||||||
|
|
||||||
|
UniqueMessagePortId id1;
|
||||||
|
UniqueMessagePortId id2;
|
||||||
|
if (!stream->Transfer(aCx, id1, id2)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*aExtraData = mPortIdentifiers.Length();
|
||||||
|
mPortIdentifiers.AppendElement(id1.release());
|
||||||
|
mPortIdentifiers.AppendElement(id2.release());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -1301,6 +1428,31 @@ void StructuredCloneHolder::CustomFreeTransferHandler(
|
||||||
delete data;
|
delete data;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (aTag == SCTAG_DOM_READABLESTREAM || aTag == SCTAG_DOM_WRITABLESTREAM) {
|
||||||
|
MOZ_ASSERT(!aContent);
|
||||||
|
#ifdef FUZZING
|
||||||
|
if (aExtraData >= mPortIdentifiers.Length()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
MOZ_ASSERT(aExtraData < mPortIdentifiers.Length());
|
||||||
|
MessagePort::ForceClose(mPortIdentifiers[aExtraData]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aTag == SCTAG_DOM_TRANSFORMSTREAM) {
|
||||||
|
MOZ_ASSERT(!aContent);
|
||||||
|
#ifdef FUZZING
|
||||||
|
if (aExtraData + 1 >= mPortIdentifiers.Length()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
MOZ_ASSERT(aExtraData + 1 < mPortIdentifiers.Length());
|
||||||
|
MessagePort::ForceClose(mPortIdentifiers[aExtraData]);
|
||||||
|
MessagePort::ForceClose(mPortIdentifiers[aExtraData + 1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StructuredCloneHolder::CustomCanTransferHandler(
|
bool StructuredCloneHolder::CustomCanTransferHandler(
|
||||||
|
|
@ -1342,6 +1494,40 @@ bool StructuredCloneHolder::CustomCanTransferHandler(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ReadableStream* stream = nullptr;
|
||||||
|
nsresult rv = UNWRAP_OBJECT(ReadableStream, &obj, stream);
|
||||||
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
// https://streams.spec.whatwg.org/#ref-for-transfer-steps
|
||||||
|
// Step 1: If ! IsReadableStreamLocked(value) is true, throw a
|
||||||
|
// "DataCloneError" DOMException.
|
||||||
|
return !IsReadableStreamLocked(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
WritableStream* stream = nullptr;
|
||||||
|
nsresult rv = UNWRAP_OBJECT(WritableStream, &obj, stream);
|
||||||
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
// https://streams.spec.whatwg.org/#ref-for-transfer-steps①
|
||||||
|
// Step 1: If ! IsWritableStreamLocked(value) is true, throw a
|
||||||
|
// "DataCloneError" DOMException.
|
||||||
|
return !IsWritableStreamLocked(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
TransformStream* stream = nullptr;
|
||||||
|
nsresult rv = UNWRAP_OBJECT(TransformStream, &obj, stream);
|
||||||
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
// https://streams.spec.whatwg.org/#ref-for-transfer-steps②
|
||||||
|
// Step 3 + 4: If ! Is{Readable,Writable}StreamLocked(value) is true,
|
||||||
|
// throw a "DataCloneError" DOMException.
|
||||||
|
return !IsReadableStreamLocked(stream->Readable()) &&
|
||||||
|
!IsWritableStreamLocked(stream->Writable());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -335,6 +335,8 @@ class StructuredCloneHolder : public StructuredCloneHolderBase {
|
||||||
|
|
||||||
void SameProcessScopeRequired(bool* aSameProcessScopeRequired);
|
void SameProcessScopeRequired(bool* aSameProcessScopeRequired);
|
||||||
|
|
||||||
|
already_AddRefed<MessagePort> ReceiveMessagePort(uint64_t aIndex);
|
||||||
|
|
||||||
bool mSupportsCloning;
|
bool mSupportsCloning;
|
||||||
bool mSupportsTransferring;
|
bool mSupportsTransferring;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -140,6 +140,12 @@ enum StructuredCloneTags : uint32_t {
|
||||||
|
|
||||||
SCTAG_DOM_CLONED_ERROR_OBJECT,
|
SCTAG_DOM_CLONED_ERROR_OBJECT,
|
||||||
|
|
||||||
|
SCTAG_DOM_READABLESTREAM,
|
||||||
|
|
||||||
|
SCTAG_DOM_WRITABLESTREAM,
|
||||||
|
|
||||||
|
SCTAG_DOM_TRANSFORMSTREAM,
|
||||||
|
|
||||||
// IMPORTANT: If you plan to add an new IDB tag, it _must_ be add before the
|
// IMPORTANT: If you plan to add an new IDB tag, it _must_ be add before the
|
||||||
// "less stable" tags!
|
// "less stable" tags!
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@ class EventMessageAutoOverride;
|
||||||
class ExtendableEvent;
|
class ExtendableEvent;
|
||||||
class KeyboardEvent;
|
class KeyboardEvent;
|
||||||
class MouseEvent;
|
class MouseEvent;
|
||||||
|
class MessageEvent;
|
||||||
class TimeEvent;
|
class TimeEvent;
|
||||||
class UIEvent;
|
class UIEvent;
|
||||||
class WantsPopupControlCheck;
|
class WantsPopupControlCheck;
|
||||||
|
|
@ -127,6 +128,9 @@ class Event : public nsISupports, public nsWrapperCache {
|
||||||
// CustomEvent has a non-autogeneratable initCustomEvent.
|
// CustomEvent has a non-autogeneratable initCustomEvent.
|
||||||
virtual CustomEvent* AsCustomEvent() { return nullptr; }
|
virtual CustomEvent* AsCustomEvent() { return nullptr; }
|
||||||
|
|
||||||
|
// MessageEvent has a non-autogeneratable initMessageEvent and more.
|
||||||
|
virtual MessageEvent* AsMessageEvent() { return nullptr; }
|
||||||
|
|
||||||
void InitEvent(const nsAString& aEventTypeArg, bool aCanBubble,
|
void InitEvent(const nsAString& aEventTypeArg, bool aCanBubble,
|
||||||
bool aCancelable) {
|
bool aCancelable) {
|
||||||
InitEvent(aEventTypeArg, aCanBubble ? CanBubble::eYes : CanBubble::eNo,
|
InitEvent(aEventTypeArg, aCanBubble ? CanBubble::eYes : CanBubble::eNo,
|
||||||
|
|
|
||||||
|
|
@ -43,8 +43,10 @@ class MessageEvent final : public Event {
|
||||||
NS_DECL_ISUPPORTS_INHERITED
|
NS_DECL_ISUPPORTS_INHERITED
|
||||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(MessageEvent, Event)
|
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(MessageEvent, Event)
|
||||||
|
|
||||||
virtual JSObject* WrapObjectInternal(
|
JSObject* WrapObjectInternal(JSContext* aCx,
|
||||||
JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
JS::Handle<JSObject*> aGivenProto) override;
|
||||||
|
|
||||||
|
MessageEvent* AsMessageEvent() override { return this; }
|
||||||
|
|
||||||
void GetData(JSContext* aCx, JS::MutableHandle<JS::Value> aData,
|
void GetData(JSContext* aCx, JS::MutableHandle<JS::Value> aData,
|
||||||
ErrorResult& aRv);
|
ErrorResult& aRv);
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@
|
||||||
#include "mozilla/dom/ByteStreamHelpers.h"
|
#include "mozilla/dom/ByteStreamHelpers.h"
|
||||||
#include "mozilla/dom/Promise.h"
|
#include "mozilla/dom/Promise.h"
|
||||||
#include "mozilla/dom/Promise-inl.h"
|
#include "mozilla/dom/Promise-inl.h"
|
||||||
#include "mozilla/dom/PromiseNativeHandler.h"
|
|
||||||
#include "mozilla/dom/ReadableByteStreamController.h"
|
#include "mozilla/dom/ReadableByteStreamController.h"
|
||||||
#include "mozilla/dom/ReadableByteStreamControllerBinding.h"
|
#include "mozilla/dom/ReadableByteStreamControllerBinding.h"
|
||||||
#include "mozilla/dom/ReadIntoRequest.h"
|
#include "mozilla/dom/ReadIntoRequest.h"
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,8 @@ using OwningReadableStreamReader =
|
||||||
OwningReadableStreamDefaultReaderOrReadableStreamBYOBReader;
|
OwningReadableStreamDefaultReaderOrReadableStreamBYOBReader;
|
||||||
class NativeUnderlyingSource;
|
class NativeUnderlyingSource;
|
||||||
class BodyStreamHolder;
|
class BodyStreamHolder;
|
||||||
|
class UniqueMessagePortId;
|
||||||
|
class MessagePort;
|
||||||
|
|
||||||
class ReadableStream final : public nsISupports, public nsWrapperCache {
|
class ReadableStream final : public nsISupports, public nsWrapperCache {
|
||||||
public:
|
public:
|
||||||
|
|
@ -95,6 +97,15 @@ class ReadableStream final : public nsISupports, public nsWrapperCache {
|
||||||
|
|
||||||
void ReleaseObjects();
|
void ReleaseObjects();
|
||||||
|
|
||||||
|
// [Transferable]
|
||||||
|
// https://html.spec.whatwg.org/multipage/structured-data.html#transfer-steps
|
||||||
|
MOZ_CAN_RUN_SCRIPT bool Transfer(JSContext* aCx,
|
||||||
|
UniqueMessagePortId& aPortId);
|
||||||
|
// https://html.spec.whatwg.org/multipage/structured-data.html#transfer-receiving-steps
|
||||||
|
static MOZ_CAN_RUN_SCRIPT bool ReceiveTransfer(
|
||||||
|
JSContext* aCx, nsIGlobalObject* aGlobal, MessagePort& aPort,
|
||||||
|
JS::MutableHandle<JSObject*> aReturnObject);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
nsIGlobalObject* GetParentObject() const { return mGlobal; }
|
nsIGlobalObject* GetParentObject() const { return mGlobal; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@
|
||||||
#include "mozilla/HoldDropJSObjects.h"
|
#include "mozilla/HoldDropJSObjects.h"
|
||||||
#include "mozilla/dom/Promise.h"
|
#include "mozilla/dom/Promise.h"
|
||||||
#include "mozilla/dom/Promise-inl.h"
|
#include "mozilla/dom/Promise-inl.h"
|
||||||
#include "mozilla/dom/PromiseNativeHandler.h"
|
|
||||||
#include "mozilla/dom/ReadableStream.h"
|
#include "mozilla/dom/ReadableStream.h"
|
||||||
#include "mozilla/dom/ReadableStreamController.h"
|
#include "mozilla/dom/ReadableStreamController.h"
|
||||||
#include "mozilla/dom/ReadableStreamDefaultController.h"
|
#include "mozilla/dom/ReadableStreamDefaultController.h"
|
||||||
|
|
@ -503,7 +502,8 @@ void SetUpReadableStreamDefaultController(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 10.
|
// Step 10.
|
||||||
RefPtr<Promise> startPromise = Promise::Create(GetIncumbentGlobal(), aRv);
|
RefPtr<Promise> startPromise =
|
||||||
|
Promise::Create(aStream->GetParentObject(), aRv);
|
||||||
if (aRv.Failed()) {
|
if (aRv.Failed()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@
|
||||||
#include "js/TypeDecls.h"
|
#include "js/TypeDecls.h"
|
||||||
#include "js/experimental/TypedData.h"
|
#include "js/experimental/TypedData.h"
|
||||||
#include "mozilla/dom/ByteStreamHelpers.h"
|
#include "mozilla/dom/ByteStreamHelpers.h"
|
||||||
#include "mozilla/dom/PromiseNativeHandler.h"
|
|
||||||
#include "mozilla/dom/Promise-inl.h"
|
#include "mozilla/dom/Promise-inl.h"
|
||||||
#include "mozilla/dom/ReadIntoRequest.h"
|
#include "mozilla/dom/ReadIntoRequest.h"
|
||||||
#include "mozilla/dom/ReadableStream.h"
|
#include "mozilla/dom/ReadableStream.h"
|
||||||
|
|
|
||||||
1065
dom/streams/Transferable.cpp
Normal file
1065
dom/streams/Transferable.cpp
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -12,7 +12,6 @@
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
#include "mozilla/dom/Promise.h"
|
#include "mozilla/dom/Promise.h"
|
||||||
#include "mozilla/dom/Promise-inl.h"
|
#include "mozilla/dom/Promise-inl.h"
|
||||||
#include "mozilla/dom/PromiseNativeHandler.h"
|
|
||||||
#include "mozilla/dom/WritableStream.h"
|
#include "mozilla/dom/WritableStream.h"
|
||||||
#include "mozilla/dom/ReadableStream.h"
|
#include "mozilla/dom/ReadableStream.h"
|
||||||
#include "mozilla/dom/RootedDictionary.h"
|
#include "mozilla/dom/RootedDictionary.h"
|
||||||
|
|
@ -45,6 +44,13 @@ TransformStream::TransformStream(nsIGlobalObject* aGlobal) : mGlobal(aGlobal) {
|
||||||
mozilla::HoldJSObjects(this);
|
mozilla::HoldJSObjects(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TransformStream::TransformStream(nsIGlobalObject* aGlobal,
|
||||||
|
ReadableStream* aReadable,
|
||||||
|
WritableStream* aWritable)
|
||||||
|
: mGlobal(aGlobal), mReadable(aReadable), mWritable(aWritable) {
|
||||||
|
mozilla::HoldJSObjects(this);
|
||||||
|
}
|
||||||
|
|
||||||
TransformStream::~TransformStream() { mozilla::DropJSObjects(this); }
|
TransformStream::~TransformStream() { mozilla::DropJSObjects(this); }
|
||||||
|
|
||||||
JSObject* TransformStream::WrapObject(JSContext* aCx,
|
JSObject* TransformStream::WrapObject(JSContext* aCx,
|
||||||
|
|
|
||||||
|
|
@ -19,12 +19,17 @@ namespace mozilla::dom {
|
||||||
|
|
||||||
class WritableStream;
|
class WritableStream;
|
||||||
class ReadableStream;
|
class ReadableStream;
|
||||||
|
class UniqueMessagePortId;
|
||||||
|
class MessagePort;
|
||||||
|
|
||||||
class TransformStream final : public nsISupports, public nsWrapperCache {
|
class TransformStream final : public nsISupports, public nsWrapperCache {
|
||||||
public:
|
public:
|
||||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TransformStream)
|
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TransformStream)
|
||||||
|
|
||||||
|
TransformStream(nsIGlobalObject* aGlobal, ReadableStream* aReadable,
|
||||||
|
WritableStream* aWritable);
|
||||||
|
|
||||||
// Internal slot accessors
|
// Internal slot accessors
|
||||||
bool Backpressure() const { return mBackpressure; }
|
bool Backpressure() const { return mBackpressure; }
|
||||||
void SetBackpressure(bool aBackpressure) { mBackpressure = aBackpressure; }
|
void SetBackpressure(bool aBackpressure) { mBackpressure = aBackpressure; }
|
||||||
|
|
@ -42,6 +47,16 @@ class TransformStream final : public nsISupports, public nsWrapperCache {
|
||||||
MOZ_KNOWN_LIVE ReadableStream* Readable() { return mReadable; }
|
MOZ_KNOWN_LIVE ReadableStream* Readable() { return mReadable; }
|
||||||
MOZ_KNOWN_LIVE WritableStream* Writable() { return mWritable; }
|
MOZ_KNOWN_LIVE WritableStream* Writable() { return mWritable; }
|
||||||
|
|
||||||
|
// [Transferable]
|
||||||
|
// https://html.spec.whatwg.org/multipage/structured-data.html#transfer-steps
|
||||||
|
MOZ_CAN_RUN_SCRIPT bool Transfer(JSContext* aCx,
|
||||||
|
UniqueMessagePortId& aPortId1,
|
||||||
|
UniqueMessagePortId& aPortId2);
|
||||||
|
// https://html.spec.whatwg.org/multipage/structured-data.html#transfer-receiving-steps
|
||||||
|
static MOZ_CAN_RUN_SCRIPT bool ReceiveTransfer(
|
||||||
|
JSContext* aCx, nsIGlobalObject* aGlobal, MessagePort& aPort1,
|
||||||
|
MessagePort& aPort2, JS::MutableHandle<JSObject*> aReturnObject);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
~TransformStream();
|
~TransformStream();
|
||||||
explicit TransformStream(nsIGlobalObject* aGlobal);
|
explicit TransformStream(nsIGlobalObject* aGlobal);
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@ class Promise;
|
||||||
class WritableStreamDefaultController;
|
class WritableStreamDefaultController;
|
||||||
class WritableStreamDefaultWriter;
|
class WritableStreamDefaultWriter;
|
||||||
class UnderlyingSinkAlgorithmsBase;
|
class UnderlyingSinkAlgorithmsBase;
|
||||||
|
class UniqueMessagePortId;
|
||||||
|
class MessagePort;
|
||||||
|
|
||||||
class WritableStream : public nsISupports, public nsWrapperCache {
|
class WritableStream : public nsISupports, public nsWrapperCache {
|
||||||
public:
|
public:
|
||||||
|
|
@ -41,7 +43,6 @@ class WritableStream : public nsISupports, public nsWrapperCache {
|
||||||
enum class WriterState { Writable, Closed, Erroring, Errored };
|
enum class WriterState { Writable, Closed, Erroring, Errored };
|
||||||
|
|
||||||
// Slot Getter/Setters:
|
// Slot Getter/Setters:
|
||||||
public:
|
|
||||||
bool Backpressure() const { return mBackpressure; }
|
bool Backpressure() const { return mBackpressure; }
|
||||||
void SetBackpressure(bool aBackpressure) { mBackpressure = aBackpressure; }
|
void SetBackpressure(bool aBackpressure) { mBackpressure = aBackpressure; }
|
||||||
|
|
||||||
|
|
@ -133,7 +134,15 @@ class WritableStream : public nsISupports, public nsWrapperCache {
|
||||||
// WritableStreamUpdateBackpressure
|
// WritableStreamUpdateBackpressure
|
||||||
void UpdateBackpressure(bool aBackpressure, ErrorResult& aRv);
|
void UpdateBackpressure(bool aBackpressure, ErrorResult& aRv);
|
||||||
|
|
||||||
public:
|
// [Transferable]
|
||||||
|
// https://html.spec.whatwg.org/multipage/structured-data.html#transfer-steps
|
||||||
|
MOZ_CAN_RUN_SCRIPT bool Transfer(JSContext* aCx,
|
||||||
|
UniqueMessagePortId& aPortId);
|
||||||
|
// https://html.spec.whatwg.org/multipage/structured-data.html#transfer-receiving-steps
|
||||||
|
static MOZ_CAN_RUN_SCRIPT bool ReceiveTransfer(
|
||||||
|
JSContext* aCx, nsIGlobalObject* aGlobal, MessagePort& aPort,
|
||||||
|
JS::MutableHandle<JSObject*> aReturnObject);
|
||||||
|
|
||||||
nsIGlobalObject* GetParentObject() const { return mGlobal; }
|
nsIGlobalObject* GetParentObject() const { return mGlobal; }
|
||||||
|
|
||||||
JSObject* WrapObject(JSContext* aCx,
|
JSObject* WrapObject(JSContext* aCx,
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,9 @@
|
||||||
#include "mozilla/dom/AbortSignal.h"
|
#include "mozilla/dom/AbortSignal.h"
|
||||||
#include "mozilla/dom/Promise.h"
|
#include "mozilla/dom/Promise.h"
|
||||||
#include "mozilla/dom/Promise-inl.h"
|
#include "mozilla/dom/Promise-inl.h"
|
||||||
#include "mozilla/dom/PromiseNativeHandler.h"
|
|
||||||
#include "mozilla/dom/WritableStream.h"
|
#include "mozilla/dom/WritableStream.h"
|
||||||
#include "mozilla/dom/WritableStreamDefaultController.h"
|
#include "mozilla/dom/WritableStreamDefaultController.h"
|
||||||
#include "mozilla/dom/WritableStreamDefaultControllerBinding.h"
|
#include "mozilla/dom/WritableStreamDefaultControllerBinding.h"
|
||||||
// #include "mozilla/dom/ReadableStreamDefaultReaderBinding.h"
|
|
||||||
#include "mozilla/dom/UnderlyingSinkBinding.h"
|
#include "mozilla/dom/UnderlyingSinkBinding.h"
|
||||||
#include "nsCycleCollectionParticipant.h"
|
#include "nsCycleCollectionParticipant.h"
|
||||||
#include "nsDebug.h"
|
#include "nsDebug.h"
|
||||||
|
|
@ -185,7 +183,8 @@ void SetUpWritableStreamDefaultController(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 16. Let startPromise be a promise resolved with startResult.
|
// Step 16. Let startPromise be a promise resolved with startResult.
|
||||||
RefPtr<Promise> startPromise = Promise::Create(GetIncumbentGlobal(), aRv);
|
RefPtr<Promise> startPromise =
|
||||||
|
Promise::Create(aStream->GetParentObject(), aRv);
|
||||||
if (aRv.Failed()) {
|
if (aRv.Failed()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ UNIFIED_SOURCES += [
|
||||||
"ReadableStreamTee.cpp",
|
"ReadableStreamTee.cpp",
|
||||||
"StreamUtils.cpp",
|
"StreamUtils.cpp",
|
||||||
"TeeState.cpp",
|
"TeeState.cpp",
|
||||||
|
"Transferable.cpp",
|
||||||
"TransformerCallbackHelpers.cpp",
|
"TransformerCallbackHelpers.cpp",
|
||||||
"TransformStream.cpp",
|
"TransformStream.cpp",
|
||||||
"TransformStreamDefaultController.cpp",
|
"TransformStreamDefaultController.cpp",
|
||||||
|
|
@ -60,10 +61,13 @@ UNIFIED_SOURCES += [
|
||||||
"WritableStreamDefaultWriter.cpp",
|
"WritableStreamDefaultWriter.cpp",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
include("/ipc/chromium/chromium-config.mozbuild") # to import MessagePort.h
|
||||||
|
|
||||||
FINAL_LIBRARY = "xul"
|
FINAL_LIBRARY = "xul"
|
||||||
|
|
||||||
LOCAL_INCLUDES += [
|
LOCAL_INCLUDES += [
|
||||||
"/dom/base",
|
"/dom/base",
|
||||||
|
"/dom/ipc",
|
||||||
]
|
]
|
||||||
|
|
||||||
# MOCHITEST_MANIFESTS += ["tests/mochitest.ini"]
|
# MOCHITEST_MANIFESTS += ["tests/mochitest.ini"]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
[Exposed=*,
|
[Exposed=*,
|
||||||
//Transferable See Bug 1734240
|
//Transferable See Bug 1562065
|
||||||
]
|
]
|
||||||
interface ReadableStream {
|
interface ReadableStream {
|
||||||
[Throws]
|
[Throws]
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ namespace net {
|
||||||
|
|
||||||
class ChannelEvent;
|
class ChannelEvent;
|
||||||
class ChannelEventQueue;
|
class ChannelEventQueue;
|
||||||
|
class MessageEvent;
|
||||||
|
|
||||||
class WebSocketChannelChild final : public BaseWebSocketChannel,
|
class WebSocketChannelChild final : public BaseWebSocketChannel,
|
||||||
public PWebSocketChild,
|
public PWebSocketChild,
|
||||||
|
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
[messagechannel.any.sharedworker.html]
|
|
||||||
[A subclass instance will be received as its closest transferable superclass]
|
|
||||||
expected: PRECONDITION_FAILED
|
|
||||||
|
|
||||||
|
|
||||||
[messagechannel.any.html]
|
|
||||||
[A subclass instance will be received as its closest transferable superclass]
|
|
||||||
expected: PRECONDITION_FAILED
|
|
||||||
|
|
||||||
|
|
||||||
[messagechannel.any.worker.html]
|
|
||||||
[A subclass instance will be received as its closest transferable superclass]
|
|
||||||
expected: PRECONDITION_FAILED
|
|
||||||
|
|
||||||
|
|
||||||
[messagechannel.any.serviceworker.html]
|
|
||||||
[A subclass instance will be received as its closest transferable superclass]
|
|
||||||
expected: PRECONDITION_FAILED
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
[window-postmessage.window.html]
|
|
||||||
[A subclass instance will be received as its closest transferable superclass]
|
|
||||||
expected: PRECONDITION_FAILED
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
[structured-clone.any.html]
|
|
||||||
[A subclass instance will be received as its closest transferable superclass]
|
|
||||||
expected: PRECONDITION_FAILED
|
|
||||||
|
|
||||||
|
|
||||||
[structured-clone.any.worker.html]
|
|
||||||
[A subclass instance will be received as its closest transferable superclass]
|
|
||||||
expected: PRECONDITION_FAILED
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
[deserialize-error.window.html]
|
|
||||||
expected: ERROR
|
|
||||||
[a ReadableStream deserialization failure should result in a DataCloneError]
|
|
||||||
expected: TIMEOUT
|
|
||||||
|
|
||||||
[a WritableStream deserialization failure should result in a DataCloneError]
|
|
||||||
expected: TIMEOUT
|
|
||||||
|
|
||||||
|
|
@ -1,49 +1,3 @@
|
||||||
[readable-stream.html]
|
[readable-stream.html]
|
||||||
[sending ten chunks on demand should work]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[race between cancel() and enqueue() should be benign]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[transferring a non-serializable chunk should error both sides]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[stream cancel should not wait for underlying source cancel]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[cancel should abort a pending read()]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[race between cancel() and error() should leave sides in different states]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[cancel should be propagated to the original]
|
[cancel should be propagated to the original]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[race between cancel() and close() should be benign]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[errors should be passed through]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[the extra queue from transferring is counted in chunks]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[sending one chunk through a transferred stream should work]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[transferring a stream should relieve backpressure]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[sending ten chunks through a transferred stream should work]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[serialization should not happen until the value is read]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[sending ten chunks one at a time should work]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[transferring a stream should add one chunk to the queue size]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,45 +2,18 @@
|
||||||
[a TypeError message should not be preserved if it is inherited]
|
[a TypeError message should not be preserved if it is inherited]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[DOMException errors should be preserved]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[reason with a simple value of '3' should be preserved]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[URIError should be preserved]
|
[URIError should be preserved]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[reason with a simple value of 'null' should be preserved]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[reason with a simple value of '7' should be preserved]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[a TypeError message should be converted to a string]
|
[a TypeError message should be converted to a string]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[objects that can be completely expressed in JSON should be preserved]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[reason with a simple value of 'true' should be preserved]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[TypeError should be preserved]
|
[TypeError should be preserved]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[reason with a simple value of 'undefined' should be preserved]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[RangeError should be preserved]
|
[RangeError should be preserved]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[reason with a simple value of 'NaN' should be preserved]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[objects that cannot be expressed in JSON should also be preserved]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[other attributes of a TypeError should not be preserved]
|
[other attributes of a TypeError should not be preserved]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
@ -50,24 +23,11 @@
|
||||||
[SyntaxError should be preserved]
|
[SyntaxError should be preserved]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[reason with a simple value of 'Infinity' should be preserved]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[EvalError should be preserved]
|
[EvalError should be preserved]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[reason with a simple value of '\t\r\n' should be preserved]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[the type and message of a TypeError should be preserved]
|
[the type and message of a TypeError should be preserved]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[reason with a simple value of 'hi' should be preserved]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[reason with a simple value of 'false' should be preserved]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[a TypeError message should not be preserved if it is a getter]
|
[a TypeError message should not be preserved if it is a getter]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
[service-worker.https.html]
|
|
||||||
expected:
|
|
||||||
if (os == "android") and debug and not swgl: [OK, ERROR]
|
|
||||||
[serviceWorker.controller.postMessage should be able to transfer a ReadableStream]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[postMessage in a service worker should be able to transfer ReadableStream]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
[shared-worker.html]
|
|
||||||
[postMessage in a worker should be able to transfer a ReadableStream]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[worker.postMessage should be able to transfer a ReadableStream]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
[transform-stream.html]
|
|
||||||
[piping through transferred transforms should work]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[window.postMessage should be able to transfer a TransformStream]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
[window.html]
|
|
||||||
[transfer to and from an iframe should work]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[the same ReadableStream posted multiple times should arrive together]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[port.postMessage should be able to transfer a ReadableStream]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[window.postMessage should be able to transfer a ReadableStream]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
[worker.html]
|
|
||||||
expected:
|
|
||||||
if (os == "win") and not debug and (processor == "x86_64"): [OK, ERROR]
|
|
||||||
[terminating a worker should not error the stream]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[postMessage in a worker should be able to transfer a ReadableStream]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[worker.postMessage should be able to transfer a ReadableStream]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
@ -1,22 +1,6 @@
|
||||||
[writable-stream.html]
|
[writable-stream.html]
|
||||||
[window.postMessage should be able to transfer a WritableStream]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[second write should wait for first underlying write to complete]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[abort() should work]
|
[abort() should work]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[window.postMessage should be able to transfer a {readable, writable} pair]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[writing a unclonable object should error the stream]
|
[writing a unclonable object should error the stream]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[effective queue size of a transferred writable should be 2]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[desiredSize for a newly-transferred stream should be 1]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
[dedicated.html]
|
|
||||||
[A subclass instance will be received as its closest transferable superclass]
|
|
||||||
expected: PRECONDITION_FAILED
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
[shared.html]
|
|
||||||
disabled:
|
|
||||||
if os == "win": Bug 1661351
|
|
||||||
[A subclass instance will be received as its closest transferable superclass]
|
|
||||||
expected: PRECONDITION_FAILED
|
|
||||||
|
|
@ -0,0 +1,219 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
function receiveEventOnce(target, name) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
target.addEventListener(
|
||||||
|
name,
|
||||||
|
ev => {
|
||||||
|
resolve(ev);
|
||||||
|
},
|
||||||
|
{ once: true }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function postAndTestMessageEvent(data, transfer, title) {
|
||||||
|
postMessage(data, "*", transfer);
|
||||||
|
const messagePortCount = transfer.filter(i => i instanceof MessagePort)
|
||||||
|
.length;
|
||||||
|
const ev = await receiveEventOnce(window, "message");
|
||||||
|
assert_equals(
|
||||||
|
ev.ports.length,
|
||||||
|
messagePortCount,
|
||||||
|
`Correct number of ports ${title}`
|
||||||
|
);
|
||||||
|
for (const [i, port] of ev.ports.entries()) {
|
||||||
|
assert_true(
|
||||||
|
port instanceof MessagePort,
|
||||||
|
`ports[${i}] include MessagePort ${title}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
for (const [key, value] of Object.entries(data)) {
|
||||||
|
assert_true(
|
||||||
|
ev.data[key] instanceof value.constructor,
|
||||||
|
`data.${key} has correct interface ${value.constructor.name} ${title}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function transferMessagePortWithOrder1(stream) {
|
||||||
|
const channel = new MessageChannel();
|
||||||
|
await postAndTestMessageEvent(
|
||||||
|
{ stream, port2: channel.port2 },
|
||||||
|
[stream, channel.port2],
|
||||||
|
`when transferring [${stream.constructor.name}, MessagePort]`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function transferMessagePortWithOrder2(stream) {
|
||||||
|
const channel = new MessageChannel();
|
||||||
|
await postAndTestMessageEvent(
|
||||||
|
{ stream, port2: channel.port2 },
|
||||||
|
[channel.port2, stream],
|
||||||
|
`when transferring [MessagePort, ${stream.constructor.name}]`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function transferMessagePortWithOrder3(stream) {
|
||||||
|
const channel = new MessageChannel();
|
||||||
|
await postAndTestMessageEvent(
|
||||||
|
{ port1: channel.port1, stream, port2: channel.port2 },
|
||||||
|
[channel.port1, stream, channel.port2],
|
||||||
|
`when transferring [MessagePort, ${stream.constructor.name}, MessagePort]`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function transferMessagePortWithOrder4(stream) {
|
||||||
|
const channel = new MessageChannel();
|
||||||
|
await postAndTestMessageEvent(
|
||||||
|
{},
|
||||||
|
[channel.port1, stream, channel.port2],
|
||||||
|
`when transferring [MessagePort, ${stream.constructor.name}, MessagePort] but with empty data`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function transferMessagePortWithOrder5(stream) {
|
||||||
|
const channel = new MessageChannel();
|
||||||
|
await postAndTestMessageEvent(
|
||||||
|
{ port2: channel.port2, port1: channel.port1, stream },
|
||||||
|
[channel.port1, stream, channel.port2],
|
||||||
|
`when transferring [MessagePort, ${stream.constructor.name}, MessagePort] but with data having different order`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function transferMessagePortWithOrder6(stream) {
|
||||||
|
const channel = new MessageChannel();
|
||||||
|
await postAndTestMessageEvent(
|
||||||
|
{ port2: channel.port2, port1: channel.port1 },
|
||||||
|
[channel.port1, stream, channel.port2],
|
||||||
|
`when transferring [MessagePort, ${stream.constructor.name}, MessagePort] but with stream not being in the data`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function transferMessagePortWithOrder7(stream) {
|
||||||
|
const channel = new MessageChannel();
|
||||||
|
await postAndTestMessageEvent(
|
||||||
|
{ stream },
|
||||||
|
[channel.port1, stream, channel.port2],
|
||||||
|
`when transferring [MessagePort, ${stream.constructor.name}, MessagePort] but with ports not being in the data`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function transferMessagePortWith(constructor) {
|
||||||
|
await transferMessagePortWithOrder1(new constructor());
|
||||||
|
await transferMessagePortWithOrder2(new constructor());
|
||||||
|
await transferMessagePortWithOrder3(new constructor());
|
||||||
|
}
|
||||||
|
|
||||||
|
async function advancedTransferMesagePortWith(constructor) {
|
||||||
|
await transferMessagePortWithOrder4(new constructor());
|
||||||
|
await transferMessagePortWithOrder5(new constructor());
|
||||||
|
await transferMessagePortWithOrder6(new constructor());
|
||||||
|
await transferMessagePortWithOrder7(new constructor());
|
||||||
|
}
|
||||||
|
|
||||||
|
async function mixedTransferMessagePortWithOrder1() {
|
||||||
|
const channel = new MessageChannel();
|
||||||
|
const readable = new ReadableStream();
|
||||||
|
const writable = new WritableStream();
|
||||||
|
const transform = new TransformStream();
|
||||||
|
await postAndTestMessageEvent(
|
||||||
|
{
|
||||||
|
readable,
|
||||||
|
writable,
|
||||||
|
transform,
|
||||||
|
port1: channel.port1,
|
||||||
|
port2: channel.port2,
|
||||||
|
},
|
||||||
|
[readable, writable, transform, channel.port1, channel.port2],
|
||||||
|
`when transferring [ReadableStream, WritableStream, TransformStream, MessagePort, MessagePort]`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function mixedTransferMessagePortWithOrder2() {
|
||||||
|
const channel = new MessageChannel();
|
||||||
|
const readable = new ReadableStream();
|
||||||
|
const writable = new WritableStream();
|
||||||
|
const transform = new TransformStream();
|
||||||
|
await postAndTestMessageEvent(
|
||||||
|
{ readable, writable, transform },
|
||||||
|
[transform, channel.port1, readable, channel.port2, writable],
|
||||||
|
`when transferring [TransformStream, MessagePort, ReadableStream, MessagePort, WritableStream]`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function mixedTransferMessagePortWithOrder3() {
|
||||||
|
const channel = new MessageChannel();
|
||||||
|
const readable1 = new ReadableStream();
|
||||||
|
const readable2 = new ReadableStream();
|
||||||
|
const writable1 = new WritableStream();
|
||||||
|
const writable2 = new WritableStream();
|
||||||
|
const transform1 = new TransformStream();
|
||||||
|
const transform2 = new TransformStream();
|
||||||
|
await postAndTestMessageEvent(
|
||||||
|
{ readable1, writable1, transform1, readable2, writable2, transform2 },
|
||||||
|
[
|
||||||
|
transform2,
|
||||||
|
channel.port1,
|
||||||
|
readable1,
|
||||||
|
channel.port2,
|
||||||
|
writable2,
|
||||||
|
readable2,
|
||||||
|
writable1,
|
||||||
|
transform1,
|
||||||
|
],
|
||||||
|
`when transferring [TransformStream, MessagePort, ReadableStream, MessagePort, WritableStream, ReadableStream, WritableStream, TransformStream] but with the data having different order`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function mixedTransferMesagePortWith() {
|
||||||
|
await mixedTransferMessagePortWithOrder1();
|
||||||
|
await mixedTransferMessagePortWithOrder2();
|
||||||
|
await mixedTransferMessagePortWithOrder3();
|
||||||
|
}
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
await transferMessagePortWith(ReadableStream);
|
||||||
|
}, "Transferring a MessagePort with a ReadableStream should set `.ports`");
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
await transferMessagePortWith(WritableStream);
|
||||||
|
}, "Transferring a MessagePort with a WritableStream should set `.ports`");
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
await transferMessagePortWith(TransformStream);
|
||||||
|
}, "Transferring a MessagePort with a TransformStream should set `.ports`");
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
await transferMessagePortWith(ReadableStream);
|
||||||
|
}, "Transferring a MessagePort with a ReadableStream should set `.ports`, advanced");
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
await transferMessagePortWith(WritableStream);
|
||||||
|
}, "Transferring a MessagePort with a WritableStream should set `.ports`, advanced");
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
await transferMessagePortWith(TransformStream);
|
||||||
|
}, "Transferring a MessagePort with a TransformStream should set `.ports`, advanced");
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
await mixedTransferMesagePortWith();
|
||||||
|
}, "Transferring a MessagePort with multiple streams should set `.ports`");
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
assert_throws_dom("DataCloneError", () =>
|
||||||
|
postMessage({ stream: new ReadableStream() }, "*")
|
||||||
|
);
|
||||||
|
}, "ReadableStream must not be serializable");
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
assert_throws_dom("DataCloneError", () =>
|
||||||
|
postMessage({ stream: new WritableStream() }, "*")
|
||||||
|
);
|
||||||
|
}, "WritableStream must not be serializable");
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
assert_throws_dom("DataCloneError", () =>
|
||||||
|
postMessage({ stream: new TransformStream() }, "*")
|
||||||
|
);
|
||||||
|
}, "TransformStream must not be serializable");
|
||||||
Loading…
Reference in a new issue