From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- dom/broadcastchannel/BroadcastChannel.cpp | 466 +++++++++++++++++++++ dom/broadcastchannel/BroadcastChannel.h | 93 ++++ dom/broadcastchannel/BroadcastChannelChild.cpp | 48 +++ dom/broadcastchannel/BroadcastChannelChild.h | 53 +++ dom/broadcastchannel/BroadcastChannelParent.cpp | 71 ++++ dom/broadcastchannel/BroadcastChannelParent.h | 46 ++ dom/broadcastchannel/BroadcastChannelService.cpp | 178 ++++++++ dom/broadcastchannel/BroadcastChannelService.h | 47 +++ dom/broadcastchannel/PBroadcastChannel.ipdl | 36 ++ dom/broadcastchannel/moz.build | 30 ++ dom/broadcastchannel/tests/blank.html | 2 + .../tests/broadcastchannel_sharedWorker.js | 17 + .../tests/broadcastchannel_worker_alive.js | 7 + dom/broadcastchannel/tests/browser.toml | 5 + .../tests/browser_private_browsing.js | 93 ++++ dom/broadcastchannel/tests/file_mozbrowser.html | 20 + dom/broadcastchannel/tests/file_mozbrowser2.html | 21 + .../tests/iframe_broadcastchannel.html | 33 ++ dom/broadcastchannel/tests/iframe_mozbrowser.html | 15 + dom/broadcastchannel/tests/iframe_mozbrowser2.html | 15 + dom/broadcastchannel/tests/mochitest.toml | 41 ++ dom/broadcastchannel/tests/testUrl1_bfcache.html | 18 + dom/broadcastchannel/tests/testUrl2_bfcache.html | 12 + dom/broadcastchannel/tests/test_bfcache.html | 120 ++++++ .../tests/test_broadcastchannel_basic.html | 67 +++ .../tests/test_broadcastchannel_close.html | 61 +++ .../tests/test_broadcastchannel_self.html | 37 ++ .../tests/test_broadcastchannel_sharedWorker.html | 52 +++ .../tests/test_broadcastchannel_worker_alive.html | 56 +++ dom/broadcastchannel/tests/test_dataCloning.html | 27 ++ dom/broadcastchannel/tests/test_dataURL.html | 35 ++ .../tests/test_event_listener_leaks.html | 55 +++ dom/broadcastchannel/tests/test_invalidState.html | 27 ++ .../tests/test_message_after_close.html | 31 ++ dom/broadcastchannel/tests/test_ordering.html | 64 +++ 35 files changed, 1999 insertions(+) create mode 100644 dom/broadcastchannel/BroadcastChannel.cpp create mode 100644 dom/broadcastchannel/BroadcastChannel.h create mode 100644 dom/broadcastchannel/BroadcastChannelChild.cpp create mode 100644 dom/broadcastchannel/BroadcastChannelChild.h create mode 100644 dom/broadcastchannel/BroadcastChannelParent.cpp create mode 100644 dom/broadcastchannel/BroadcastChannelParent.h create mode 100644 dom/broadcastchannel/BroadcastChannelService.cpp create mode 100644 dom/broadcastchannel/BroadcastChannelService.h create mode 100644 dom/broadcastchannel/PBroadcastChannel.ipdl create mode 100644 dom/broadcastchannel/moz.build create mode 100644 dom/broadcastchannel/tests/blank.html create mode 100644 dom/broadcastchannel/tests/broadcastchannel_sharedWorker.js create mode 100644 dom/broadcastchannel/tests/broadcastchannel_worker_alive.js create mode 100644 dom/broadcastchannel/tests/browser.toml create mode 100644 dom/broadcastchannel/tests/browser_private_browsing.js create mode 100644 dom/broadcastchannel/tests/file_mozbrowser.html create mode 100644 dom/broadcastchannel/tests/file_mozbrowser2.html create mode 100644 dom/broadcastchannel/tests/iframe_broadcastchannel.html create mode 100644 dom/broadcastchannel/tests/iframe_mozbrowser.html create mode 100644 dom/broadcastchannel/tests/iframe_mozbrowser2.html create mode 100644 dom/broadcastchannel/tests/mochitest.toml create mode 100644 dom/broadcastchannel/tests/testUrl1_bfcache.html create mode 100644 dom/broadcastchannel/tests/testUrl2_bfcache.html create mode 100644 dom/broadcastchannel/tests/test_bfcache.html create mode 100644 dom/broadcastchannel/tests/test_broadcastchannel_basic.html create mode 100644 dom/broadcastchannel/tests/test_broadcastchannel_close.html create mode 100644 dom/broadcastchannel/tests/test_broadcastchannel_self.html create mode 100644 dom/broadcastchannel/tests/test_broadcastchannel_sharedWorker.html create mode 100644 dom/broadcastchannel/tests/test_broadcastchannel_worker_alive.html create mode 100644 dom/broadcastchannel/tests/test_dataCloning.html create mode 100644 dom/broadcastchannel/tests/test_dataURL.html create mode 100644 dom/broadcastchannel/tests/test_event_listener_leaks.html create mode 100644 dom/broadcastchannel/tests/test_invalidState.html create mode 100644 dom/broadcastchannel/tests/test_message_after_close.html create mode 100644 dom/broadcastchannel/tests/test_ordering.html (limited to 'dom/broadcastchannel') diff --git a/dom/broadcastchannel/BroadcastChannel.cpp b/dom/broadcastchannel/BroadcastChannel.cpp new file mode 100644 index 0000000000..c89231badf --- /dev/null +++ b/dom/broadcastchannel/BroadcastChannel.cpp @@ -0,0 +1,466 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "BroadcastChannel.h" +#include "BroadcastChannelChild.h" +#include "mozilla/dom/BroadcastChannelBinding.h" +#include "mozilla/dom/Navigator.h" +#include "mozilla/dom/File.h" +#include "mozilla/dom/MessageEvent.h" +#include "mozilla/dom/MessageEventBinding.h" +#include "mozilla/dom/StructuredCloneHolder.h" +#include "mozilla/dom/ipc/StructuredCloneData.h" +#include "mozilla/dom/RefMessageBodyService.h" +#include "mozilla/dom/RootedDictionary.h" +#include "mozilla/dom/SharedMessageBody.h" +#include "mozilla/dom/WorkerScope.h" +#include "mozilla/dom/WorkerRef.h" +#include "mozilla/dom/WorkerRunnable.h" +#include "mozilla/ipc/BackgroundChild.h" +#include "mozilla/ipc/BackgroundUtils.h" +#include "mozilla/ipc/PBackgroundChild.h" +#include "mozilla/StorageAccess.h" + +#include "nsICookieJarSettings.h" +#include "mozilla/dom/Document.h" + +#ifdef XP_WIN +# undef PostMessage +#endif + +namespace mozilla { + +using namespace ipc; + +namespace dom { + +using namespace ipc; + +namespace { + +class CloseRunnable final : public DiscardableRunnable { + public: + explicit CloseRunnable(BroadcastChannel* aBC) + : DiscardableRunnable("BroadcastChannel CloseRunnable"), mBC(aBC) { + MOZ_ASSERT(mBC); + } + + NS_IMETHOD Run() override { + mBC->Shutdown(); + return NS_OK; + } + + private: + ~CloseRunnable() = default; + + RefPtr mBC; +}; + +class TeardownRunnable { + protected: + explicit TeardownRunnable(BroadcastChannelChild* aActor) : mActor(aActor) { + MOZ_ASSERT(mActor); + } + + void RunInternal() { + MOZ_ASSERT(mActor); + if (!mActor->IsActorDestroyed()) { + mActor->SendClose(); + } + } + + protected: + virtual ~TeardownRunnable() = default; + + private: + RefPtr mActor; +}; + +class TeardownRunnableOnMainThread final : public Runnable, + public TeardownRunnable { + public: + explicit TeardownRunnableOnMainThread(BroadcastChannelChild* aActor) + : Runnable("TeardownRunnableOnMainThread"), TeardownRunnable(aActor) {} + + NS_IMETHOD Run() override { + RunInternal(); + return NS_OK; + } +}; + +class TeardownRunnableOnWorker final : public WorkerControlRunnable, + public TeardownRunnable { + public: + TeardownRunnableOnWorker(WorkerPrivate* aWorkerPrivate, + BroadcastChannelChild* aActor) + : WorkerControlRunnable(aWorkerPrivate, "TeardownRunnableOnWorker", + WorkerThread), + TeardownRunnable(aActor) {} + + bool WorkerRun(JSContext*, WorkerPrivate*) override { + RunInternal(); + return true; + } + + bool PreDispatch(WorkerPrivate* aWorkerPrivate) override { return true; } + + void PostDispatch(WorkerPrivate* aWorkerPrivate, + bool aDispatchResult) override {} + + bool PreRun(WorkerPrivate* aWorkerPrivate) override { return true; } + + void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, + bool aRunResult) override {} +}; + +} // namespace + +BroadcastChannel::BroadcastChannel(nsIGlobalObject* aGlobal, + const nsAString& aChannel, + const nsID& aPortUUID) + : DOMEventTargetHelper(aGlobal), + mRefMessageBodyService(RefMessageBodyService::GetOrCreate()), + mChannel(aChannel), + mState(StateActive), + mPortUUID(aPortUUID) { + MOZ_ASSERT(aGlobal); + KeepAliveIfHasListenersFor(nsGkAtoms::onmessage); +} + +BroadcastChannel::~BroadcastChannel() { + Shutdown(); + MOZ_ASSERT(!mWorkerRef); +} + +JSObject* BroadcastChannel::WrapObject(JSContext* aCx, + JS::Handle aGivenProto) { + return BroadcastChannel_Binding::Wrap(aCx, this, aGivenProto); +} + +/* static */ +already_AddRefed BroadcastChannel::Constructor( + const GlobalObject& aGlobal, const nsAString& aChannel, ErrorResult& aRv) { + nsCOMPtr global = do_QueryInterface(aGlobal.GetAsSupports()); + if (NS_WARN_IF(!global)) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + nsID portUUID = {}; + aRv = nsID::GenerateUUIDInPlace(portUUID); + if (aRv.Failed()) { + return nullptr; + } + + RefPtr bc = + new BroadcastChannel(global, aChannel, portUUID); + + nsCOMPtr storagePrincipal; + + StorageAccess storageAccess; + + nsCOMPtr cjs; + if (NS_IsMainThread()) { + nsCOMPtr window = do_QueryInterface(global); + if (NS_WARN_IF(!window)) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + nsCOMPtr incumbent = mozilla::dom::GetIncumbentGlobal(); + + if (!incumbent) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + nsCOMPtr sop = do_QueryInterface(incumbent); + if (NS_WARN_IF(!sop)) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + storagePrincipal = sop->GetEffectiveStoragePrincipal(); + if (!storagePrincipal) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } + storageAccess = StorageAllowedForWindow(window); + + Document* doc = window->GetExtantDoc(); + if (doc) { + cjs = doc->CookieJarSettings(); + } + } else { + JSContext* cx = aGlobal.Context(); + + WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx); + MOZ_ASSERT(workerPrivate); + + RefPtr workerRef = StrongWorkerRef::Create( + workerPrivate, "BroadcastChannel", [bc]() { bc->Shutdown(); }); + // We are already shutting down the worker. Let's return a non-active + // object. + if (NS_WARN_IF(!workerRef)) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + storageAccess = workerPrivate->StorageAccess(); + + storagePrincipal = workerPrivate->GetEffectiveStoragePrincipal(); + + bc->mWorkerRef = workerRef; + + cjs = workerPrivate->CookieJarSettings(); + } + + // We want to allow opaque origins. + if (!storagePrincipal->GetIsNullPrincipal() && + (storageAccess == StorageAccess::eDeny || + (ShouldPartitionStorage(storageAccess) && + !StoragePartitioningEnabled(storageAccess, cjs)))) { + aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); + return nullptr; + } + + // Register this component to PBackground. + PBackgroundChild* actorChild = BackgroundChild::GetOrCreateForCurrentThread(); + if (NS_WARN_IF(!actorChild)) { + // Firefox is probably shutting down. Let's return a 'generic' error. + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + nsAutoCString origin; + aRv = storagePrincipal->GetOrigin(origin); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + nsString originForEvents; + aRv = nsContentUtils::GetWebExposedOriginSerialization(storagePrincipal, + originForEvents); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + PrincipalInfo storagePrincipalInfo; + aRv = PrincipalToPrincipalInfo(storagePrincipal, &storagePrincipalInfo); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + PBroadcastChannelChild* actor = actorChild->SendPBroadcastChannelConstructor( + storagePrincipalInfo, origin, nsString(aChannel)); + if (!actor) { + // The PBackground actor is shutting down, return a 'generic' error. + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + bc->mActor = static_cast(actor); + bc->mActor->SetParent(bc); + bc->mOriginForEvents = std::move(originForEvents); + + return bc.forget(); +} + +void BroadcastChannel::PostMessage(JSContext* aCx, + JS::Handle aMessage, + ErrorResult& aRv) { + if (mState != StateActive) { + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return; + } + + Maybe agentClusterId; + nsCOMPtr global = GetOwnerGlobal(); + MOZ_ASSERT(global); + if (global) { + agentClusterId = global->GetAgentClusterId(); + } + + if (!global->IsEligibleForMessaging()) { + return; + } + + RefPtr data = new SharedMessageBody( + StructuredCloneHolder::TransferringNotSupported, agentClusterId); + + data->Write(aCx, aMessage, JS::UndefinedHandleValue, mPortUUID, + mRefMessageBodyService, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + + RemoveDocFromBFCache(); + + MessageData message; + SharedMessageBody::FromSharedToMessageChild(mActor->Manager(), data, message); + mActor->SendPostMessage(message); +} + +void BroadcastChannel::Close() { + if (mState != StateActive) { + return; + } + + // We cannot call Shutdown() immediatelly because we could have some + // postMessage runnable already dispatched. Instead, we change the state to + // StateClosed and we shutdown the actor asynchrounsly. + + mState = StateClosed; + RefPtr runnable = new CloseRunnable(this); + + if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) { + NS_WARNING("Failed to dispatch to the current thread!"); + } +} + +void BroadcastChannel::Shutdown() { + mState = StateClosed; + + // The DTOR of this WorkerRef will release the worker for us. + mWorkerRef = nullptr; + + if (mActor) { + mActor->SetParent(nullptr); + + if (NS_IsMainThread()) { + RefPtr runnable = + new TeardownRunnableOnMainThread(mActor); + NS_DispatchToCurrentThread(runnable); + } else { + WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); + MOZ_ASSERT(workerPrivate); + + RefPtr runnable = + new TeardownRunnableOnWorker(workerPrivate, mActor); + runnable->Dispatch(); + } + + mActor = nullptr; + } + + IgnoreKeepAliveIfHasListenersFor(nsGkAtoms::onmessage); +} + +void BroadcastChannel::RemoveDocFromBFCache() { + if (!NS_IsMainThread()) { + return; + } + + if (nsPIDOMWindowInner* window = GetOwner()) { + window->RemoveFromBFCacheSync(); + } +} + +void BroadcastChannel::DisconnectFromOwner() { + Shutdown(); + DOMEventTargetHelper::DisconnectFromOwner(); +} + +void BroadcastChannel::MessageReceived(const MessageData& aData) { + if (NS_FAILED(CheckCurrentGlobalCorrectness())) { + RemoveDocFromBFCache(); + return; + } + + // Let's ignore messages after a close/shutdown. + if (mState != StateActive) { + return; + } + + nsCOMPtr globalObject; + + if (NS_IsMainThread()) { + globalObject = GetParentObject(); + } else { + WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); + MOZ_ASSERT(workerPrivate); + globalObject = workerPrivate->GlobalScope(); + } + + AutoJSAPI jsapi; + if (!globalObject || !jsapi.Init(globalObject)) { + NS_WARNING("Failed to initialize AutoJSAPI object."); + return; + } + + JSContext* cx = jsapi.cx(); + + RefPtr data = SharedMessageBody::FromMessageToSharedChild( + aData, StructuredCloneHolder::TransferringNotSupported); + if (NS_WARN_IF(!data)) { + DispatchError(cx); + return; + } + + IgnoredErrorResult rv; + JS::Rooted value(cx); + + data->Read(cx, &value, mRefMessageBodyService, + SharedMessageBody::ReadMethod::KeepRefMessageBody, rv); + if (NS_WARN_IF(rv.Failed())) { + JS_ClearPendingException(cx); + DispatchError(cx); + return; + } + + RemoveDocFromBFCache(); + + RootedDictionary init(cx); + init.mBubbles = false; + init.mCancelable = false; + init.mOrigin = mOriginForEvents; + init.mData = value; + + RefPtr event = + MessageEvent::Constructor(this, u"message"_ns, init); + + event->SetTrusted(true); + + DispatchEvent(*event); +} + +void BroadcastChannel::MessageDelivered(const nsID& aMessageID, + uint32_t aOtherBCs) { + mRefMessageBodyService->SetMaxCount(aMessageID, aOtherBCs); +} + +void BroadcastChannel::DispatchError(JSContext* aCx) { + RootedDictionary init(aCx); + init.mBubbles = false; + init.mCancelable = false; + init.mOrigin = mOriginForEvents; + + RefPtr event = + MessageEvent::Constructor(this, u"messageerror"_ns, init); + event->SetTrusted(true); + + DispatchEvent(*event); +} + +NS_IMPL_CYCLE_COLLECTION_CLASS(BroadcastChannel) + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BroadcastChannel, + DOMEventTargetHelper) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BroadcastChannel, + DOMEventTargetHelper) + tmp->Shutdown(); +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BroadcastChannel) +NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) + +NS_IMPL_ADDREF_INHERITED(BroadcastChannel, DOMEventTargetHelper) +NS_IMPL_RELEASE_INHERITED(BroadcastChannel, DOMEventTargetHelper) + +} // namespace dom +} // namespace mozilla diff --git a/dom/broadcastchannel/BroadcastChannel.h b/dom/broadcastchannel/BroadcastChannel.h new file mode 100644 index 0000000000..280913e8f8 --- /dev/null +++ b/dom/broadcastchannel/BroadcastChannel.h @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_BroadcastChannel_h +#define mozilla_dom_BroadcastChannel_h + +#include "mozilla/Attributes.h" +#include "mozilla/DOMEventTargetHelper.h" +#include "nsTArray.h" +#include "mozilla/RefPtr.h" + +class nsIGlobalObject; + +namespace mozilla { + +namespace ipc { +class PrincipalInfo; +} // namespace ipc + +namespace dom { + +class BroadcastChannelChild; +class RefMessageBodyService; +class WorkerRef; + +class BroadcastChannel final : public DOMEventTargetHelper { + friend class BroadcastChannelChild; + + using PrincipalInfo = mozilla::ipc::PrincipalInfo; + + public: + NS_DECL_ISUPPORTS_INHERITED + + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BroadcastChannel, + DOMEventTargetHelper) + + virtual JSObject* WrapObject(JSContext* aCx, + JS::Handle aGivenProto) override; + + static already_AddRefed Constructor( + const GlobalObject& aGlobal, const nsAString& aChannel, ErrorResult& aRv); + + void GetName(nsAString& aName) const { aName = mChannel; } + + void PostMessage(JSContext* aCx, JS::Handle aMessage, + ErrorResult& aRv); + + void Close(); + + IMPL_EVENT_HANDLER(message) + IMPL_EVENT_HANDLER(messageerror) + + void Shutdown(); + + private: + BroadcastChannel(nsIGlobalObject* aGlobal, const nsAString& aChannel, + const nsID& aPortUUID); + + ~BroadcastChannel(); + + void MessageReceived(const MessageData& aData); + + void MessageDelivered(const nsID& aMessageID, uint32_t aOtherBCs); + + void RemoveDocFromBFCache(); + + void DisconnectFromOwner() override; + + void DispatchError(JSContext* aCx); + + RefPtr mActor; + + RefPtr mRefMessageBodyService; + + RefPtr mWorkerRef; + + nsString mChannel; + nsString mOriginForEvents; + + enum { StateActive, StateClosed } mState; + + // This ID is used to identify the messages-by-reference sent by this port. + // See RefMessageBodyService. + nsID mPortUUID; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_BroadcastChannel_h diff --git a/dom/broadcastchannel/BroadcastChannelChild.cpp b/dom/broadcastchannel/BroadcastChannelChild.cpp new file mode 100644 index 0000000000..30e2633c5d --- /dev/null +++ b/dom/broadcastchannel/BroadcastChannelChild.cpp @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "BroadcastChannelChild.h" +#include "BroadcastChannel.h" + +namespace mozilla { + +using namespace ipc; + +namespace dom { + +BroadcastChannelChild::BroadcastChannelChild() + : mBC(nullptr), mActorDestroyed(false) {} + +BroadcastChannelChild::~BroadcastChannelChild() { MOZ_ASSERT(!mBC); } + +mozilla::ipc::IPCResult BroadcastChannelChild::RecvNotify( + const MessageData& aData) { + if (!mBC) { + // The object is going to be deleted soon. No notify is required. + return IPC_OK(); + } + + mBC->MessageReceived(aData); + return IPC_OK(); +} + +mozilla::ipc::IPCResult BroadcastChannelChild::RecvRefMessageDelivered( + const nsID& aMessageID, const uint32_t& aOtherBCs) { + if (!mBC) { + // The object is going to be deleted soon. No notify is required. + return IPC_OK(); + } + + mBC->MessageDelivered(aMessageID, aOtherBCs); + return IPC_OK(); +} + +void BroadcastChannelChild::ActorDestroy(ActorDestroyReason aWhy) { + mActorDestroyed = true; +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/broadcastchannel/BroadcastChannelChild.h b/dom/broadcastchannel/BroadcastChannelChild.h new file mode 100644 index 0000000000..5c5cae4fd7 --- /dev/null +++ b/dom/broadcastchannel/BroadcastChannelChild.h @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_BroadcastChannelChild_h +#define mozilla_dom_BroadcastChannelChild_h + +#include "mozilla/dom/PBroadcastChannelChild.h" + +namespace mozilla { + +namespace ipc { +class BackgroundChildImpl; +} // namespace ipc + +namespace dom { + +class BroadcastChannel; + +class BroadcastChannelChild final : public PBroadcastChannelChild { + friend class mozilla::ipc::BackgroundChildImpl; + + public: + NS_INLINE_DECL_REFCOUNTING(BroadcastChannelChild) + + void SetParent(BroadcastChannel* aBC) { mBC = aBC; } + + virtual mozilla::ipc::IPCResult RecvNotify(const MessageData& aData) override; + + virtual mozilla::ipc::IPCResult RecvRefMessageDelivered( + const nsID& aMessageID, const uint32_t& aOtherBCs) override; + + bool IsActorDestroyed() const { return mActorDestroyed; } + + private: + BroadcastChannelChild(); + ~BroadcastChannelChild(); + + virtual void ActorDestroy(ActorDestroyReason aWhy) override; + + // This raw pointer is actually the parent object. + // It's set to null when the parent object is deleted. + BroadcastChannel* mBC; + + bool mActorDestroyed; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_BroadcastChannelChild_h diff --git a/dom/broadcastchannel/BroadcastChannelParent.cpp b/dom/broadcastchannel/BroadcastChannelParent.cpp new file mode 100644 index 0000000000..56c528c933 --- /dev/null +++ b/dom/broadcastchannel/BroadcastChannelParent.cpp @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "BroadcastChannelParent.h" +#include "BroadcastChannelService.h" +#include "mozilla/dom/File.h" +#include "mozilla/dom/IPCBlobUtils.h" +#include "mozilla/ipc/BackgroundParent.h" +#include "mozilla/ipc/IPCStreamUtils.h" +#include "mozilla/Unused.h" + +namespace mozilla { + +using namespace ipc; + +namespace dom { + +BroadcastChannelParent::BroadcastChannelParent( + const nsAString& aOriginChannelKey) + : mService(BroadcastChannelService::GetOrCreate()), + mOriginChannelKey(aOriginChannelKey) { + AssertIsOnBackgroundThread(); + mService->RegisterActor(this, mOriginChannelKey); +} + +BroadcastChannelParent::~BroadcastChannelParent() { + AssertIsOnBackgroundThread(); +} + +mozilla::ipc::IPCResult BroadcastChannelParent::RecvPostMessage( + const MessageData& aData) { + AssertIsOnBackgroundThread(); + + if (NS_WARN_IF(!mService)) { + return IPC_FAIL_NO_REASON(this); + } + + mService->PostMessage(this, aData, mOriginChannelKey); + return IPC_OK(); +} + +mozilla::ipc::IPCResult BroadcastChannelParent::RecvClose() { + AssertIsOnBackgroundThread(); + + if (NS_WARN_IF(!mService)) { + return IPC_FAIL_NO_REASON(this); + } + + mService->UnregisterActor(this, mOriginChannelKey); + mService = nullptr; + + Unused << Send__delete__(this); + + return IPC_OK(); +} + +void BroadcastChannelParent::ActorDestroy(ActorDestroyReason aWhy) { + AssertIsOnBackgroundThread(); + + if (mService) { + // This object is about to be released and with it, also mService will be + // released too. + mService->UnregisterActor(this, mOriginChannelKey); + } +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/broadcastchannel/BroadcastChannelParent.h b/dom/broadcastchannel/BroadcastChannelParent.h new file mode 100644 index 0000000000..fdca75d213 --- /dev/null +++ b/dom/broadcastchannel/BroadcastChannelParent.h @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_BroadcastChannelParent_h +#define mozilla_dom_BroadcastChannelParent_h + +#include "mozilla/dom/PBroadcastChannelParent.h" + +namespace mozilla { + +namespace ipc { +class BackgroundParentImpl; +class PrincipalInfo; +} // namespace ipc + +namespace dom { + +class BroadcastChannelService; + +class BroadcastChannelParent final : public PBroadcastChannelParent { + friend class mozilla::ipc::BackgroundParentImpl; + + using PrincipalInfo = mozilla::ipc::PrincipalInfo; + + private: + explicit BroadcastChannelParent(const nsAString& aOriginChannelKey); + ~BroadcastChannelParent(); + + virtual mozilla::ipc::IPCResult RecvPostMessage( + const MessageData& aData) override; + + virtual mozilla::ipc::IPCResult RecvClose() override; + + virtual void ActorDestroy(ActorDestroyReason aWhy) override; + + RefPtr mService; + const nsString mOriginChannelKey; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_BroadcastChannelParent_h diff --git a/dom/broadcastchannel/BroadcastChannelService.cpp b/dom/broadcastchannel/BroadcastChannelService.cpp new file mode 100644 index 0000000000..c3dab2b28a --- /dev/null +++ b/dom/broadcastchannel/BroadcastChannelService.cpp @@ -0,0 +1,178 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "BroadcastChannelService.h" +#include "BroadcastChannelParent.h" +#include "mozilla/dom/BlobImpl.h" +#include "mozilla/dom/File.h" +#include "mozilla/dom/IPCBlobUtils.h" +#include "mozilla/ipc/BackgroundParent.h" + +#ifdef XP_WIN +# undef PostMessage +#endif + +namespace mozilla { + +using namespace ipc; + +namespace dom { + +namespace { + +BroadcastChannelService* sInstance = nullptr; + +ClonedMessageData CloneClonedMessageData(const ClonedMessageData& aOther) { + auto cloneData = SerializedStructuredCloneBuffer{}; + cloneData.data.initScope(aOther.data().data.scope()); + const bool res = cloneData.data.Append(aOther.data().data); + MOZ_RELEASE_ASSERT(res, "out of memory"); + return {std::move(cloneData), aOther.blobs(), aOther.inputStreams(), + aOther.identifiers()}; +} + +MessageData CloneMessageData(const MessageData& aOther) { + switch (aOther.data().type()) { + case MessageDataType::TClonedMessageData: + return {aOther.agentClusterId(), + CloneClonedMessageData(aOther.data().get_ClonedMessageData())}; + case MessageDataType::TRefMessageData: + return {aOther.agentClusterId(), aOther.data().get_RefMessageData()}; + default: + MOZ_CRASH("Unexpected MessageDataType type"); + } +} + +} // namespace + +BroadcastChannelService::BroadcastChannelService() { + AssertIsOnBackgroundThread(); + + // sInstance is a raw BroadcastChannelService*. + MOZ_ASSERT(!sInstance); + sInstance = this; +} + +BroadcastChannelService::~BroadcastChannelService() { + AssertIsOnBackgroundThread(); + MOZ_ASSERT(sInstance == this); + MOZ_ASSERT(mAgents.Count() == 0); + + sInstance = nullptr; +} + +// static +already_AddRefed +BroadcastChannelService::GetOrCreate() { + AssertIsOnBackgroundThread(); + + RefPtr instance = sInstance; + if (!instance) { + instance = new BroadcastChannelService(); + } + return instance.forget(); +} + +void BroadcastChannelService::RegisterActor( + BroadcastChannelParent* aParent, const nsAString& aOriginChannelKey) { + AssertIsOnBackgroundThread(); + MOZ_ASSERT(aParent); + + auto* const parents = mAgents.GetOrInsertNew(aOriginChannelKey); + + MOZ_ASSERT(!parents->Contains(aParent)); + parents->AppendElement(aParent); +} + +void BroadcastChannelService::UnregisterActor( + BroadcastChannelParent* aParent, const nsAString& aOriginChannelKey) { + AssertIsOnBackgroundThread(); + MOZ_ASSERT(aParent); + + if (auto entry = mAgents.Lookup(aOriginChannelKey)) { + entry.Data()->RemoveElement(aParent); + // remove the entry if the array is now empty + if (entry.Data()->IsEmpty()) { + entry.Remove(); + } + } else { + MOZ_CRASH("Invalid state"); + } +} + +void BroadcastChannelService::PostMessage(BroadcastChannelParent* aParent, + const MessageData& aData, + const nsAString& aOriginChannelKey) { + AssertIsOnBackgroundThread(); + MOZ_ASSERT(aParent); + + nsTArray* parents; + if (!mAgents.Get(aOriginChannelKey, &parents)) { + MOZ_CRASH("Invalid state"); + } + + // We need to keep the array alive for the life-time of this operation. + nsTArray> blobImpls; + if (aData.data().type() == MessageDataType::TClonedMessageData) { + const nsTArray& blobs = + aData.data().get_ClonedMessageData().blobs(); + if (!blobs.IsEmpty()) { + blobImpls.SetCapacity(blobs.Length()); + + for (uint32_t i = 0, len = blobs.Length(); i < len; ++i) { + RefPtr impl = IPCBlobUtils::Deserialize(blobs[i]); + + MOZ_ASSERT(impl); + blobImpls.AppendElement(impl); + } + } + } + + uint32_t selectedActorsOnSamePid = 0; + + // For each parent actor, we notify the message. + for (uint32_t i = 0; i < parents->Length(); ++i) { + BroadcastChannelParent* parent = parents->ElementAt(i); + MOZ_ASSERT(parent); + + if (parent == aParent) { + continue; + } + + if (parent->OtherPid() == aParent->OtherPid()) { + ++selectedActorsOnSamePid; + } + + // We need to have a copy of the data for this parent. + MessageData newData = CloneMessageData(aData); + MOZ_ASSERT(newData.data().type() == aData.data().type()); + + if (!blobImpls.IsEmpty()) { + nsTArray& newBlobImpls = + newData.data().get_ClonedMessageData().blobs(); + MOZ_ASSERT(blobImpls.Length() == newBlobImpls.Length()); + + // Serialize Blob objects for this message. + for (uint32_t i = 0, len = blobImpls.Length(); i < len; ++i) { + nsresult rv = IPCBlobUtils::Serialize(blobImpls[i], newBlobImpls[i]); + if (NS_WARN_IF(NS_FAILED(rv))) { + return; + } + } + } + + Unused << parent->SendNotify(newData); + } + + // If this is a refMessageData, we need to know when it can be released. + if (aData.data().type() == MessageDataType::TRefMessageData) { + Unused << aParent->SendRefMessageDelivered( + aData.data().get_RefMessageData().uuid(), selectedActorsOnSamePid); + } +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/broadcastchannel/BroadcastChannelService.h b/dom/broadcastchannel/BroadcastChannelService.h new file mode 100644 index 0000000000..5ec525d799 --- /dev/null +++ b/dom/broadcastchannel/BroadcastChannelService.h @@ -0,0 +1,47 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_BroadcastChannelService_h +#define mozilla_dom_BroadcastChannelService_h + +#include "nsISupportsImpl.h" +#include "nsHashKeys.h" +#include "nsClassHashtable.h" + +#ifdef XP_WIN +# undef PostMessage +#endif + +namespace mozilla::dom { + +class BroadcastChannelParent; +class MessageData; + +class BroadcastChannelService final { + public: + NS_INLINE_DECL_REFCOUNTING(BroadcastChannelService) + + static already_AddRefed GetOrCreate(); + + void RegisterActor(BroadcastChannelParent* aParent, + const nsAString& aOriginChannelKey); + void UnregisterActor(BroadcastChannelParent* aParent, + const nsAString& aOriginChannelKey); + + void PostMessage(BroadcastChannelParent* aParent, const MessageData& aData, + const nsAString& aOriginChannelKey); + + private: + BroadcastChannelService(); + ~BroadcastChannelService(); + + // Raw Pointers because the actors keep alive this service. + nsClassHashtable> mAgents; +}; + +} // namespace mozilla::dom + +#endif // mozilla_dom_BroadcastChannelService_h diff --git a/dom/broadcastchannel/PBroadcastChannel.ipdl b/dom/broadcastchannel/PBroadcastChannel.ipdl new file mode 100644 index 0000000000..6ff27b45d8 --- /dev/null +++ b/dom/broadcastchannel/PBroadcastChannel.ipdl @@ -0,0 +1,36 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +include protocol PBackground; + +include DOMTypes; + +using struct nsID from "nsID.h"; + +namespace mozilla { +namespace dom { + +// This protocol is used for the BroadcastChannel API +[ManualDealloc, ChildImpl=virtual, ParentImpl=virtual] +protocol PBroadcastChannel +{ + manager PBackground; + +parent: + async PostMessage(MessageData message); + async Close(); + +child: + // A message must be delivered. + async Notify(MessageData message); + + // A message has been delivered to other channels. It can be removed after + // all the actorsOnSamePid have retrieved it. + async RefMessageDelivered(nsID messageID, uint32_t actorsOnSamePid); + + async __delete__(); +}; + +} // namespace dom +} // namespace mozilla diff --git a/dom/broadcastchannel/moz.build b/dom/broadcastchannel/moz.build new file mode 100644 index 0000000000..573686bf30 --- /dev/null +++ b/dom/broadcastchannel/moz.build @@ -0,0 +1,30 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +with Files("**"): + BUG_COMPONENT = ("Core", "DOM: postMessage") + +EXPORTS.mozilla.dom += [ + "BroadcastChannel.h", +] + +UNIFIED_SOURCES += [ + "BroadcastChannel.cpp", + "BroadcastChannelChild.cpp", + "BroadcastChannelParent.cpp", + "BroadcastChannelService.cpp", +] + +IPDL_SOURCES += [ + "PBroadcastChannel.ipdl", +] + +MOCHITEST_MANIFESTS += ["tests/mochitest.toml"] +BROWSER_CHROME_MANIFESTS += ["tests/browser.toml"] + +include("/ipc/chromium/chromium-config.mozbuild") + +FINAL_LIBRARY = "xul" diff --git a/dom/broadcastchannel/tests/blank.html b/dom/broadcastchannel/tests/blank.html new file mode 100644 index 0000000000..358db717dd --- /dev/null +++ b/dom/broadcastchannel/tests/blank.html @@ -0,0 +1,2 @@ + + diff --git a/dom/broadcastchannel/tests/broadcastchannel_sharedWorker.js b/dom/broadcastchannel/tests/broadcastchannel_sharedWorker.js new file mode 100644 index 0000000000..17fb806371 --- /dev/null +++ b/dom/broadcastchannel/tests/broadcastchannel_sharedWorker.js @@ -0,0 +1,17 @@ +/* eslint-env worker */ + +onconnect = function (evt) { + evt.ports[0].onmessage = function (evt1) { + var bc = new BroadcastChannel("foobar"); + bc.addEventListener("message", function (event) { + bc.postMessage( + event.data == "hello world from the window" + ? "hello world from the worker" + : "KO" + ); + bc.close(); + }); + + evt1.target.postMessage("READY"); + }; +}; diff --git a/dom/broadcastchannel/tests/broadcastchannel_worker_alive.js b/dom/broadcastchannel/tests/broadcastchannel_worker_alive.js new file mode 100644 index 0000000000..da608c6d20 --- /dev/null +++ b/dom/broadcastchannel/tests/broadcastchannel_worker_alive.js @@ -0,0 +1,7 @@ +new BroadcastChannel("foobar").addEventListener("message", function (event) { + if (event.data != "READY") { + event.target.postMessage(event.data); + } +}); + +new BroadcastChannel("foobar").postMessage("READY"); diff --git a/dom/broadcastchannel/tests/browser.toml b/dom/broadcastchannel/tests/browser.toml new file mode 100644 index 0000000000..4162a34a68 --- /dev/null +++ b/dom/broadcastchannel/tests/browser.toml @@ -0,0 +1,5 @@ +[DEFAULT] +skip-if = ["os == 'android'"] +support-files = ["blank.html"] + +["browser_private_browsing.js"] diff --git a/dom/broadcastchannel/tests/browser_private_browsing.js b/dom/broadcastchannel/tests/browser_private_browsing.js new file mode 100644 index 0000000000..e61e8ae58e --- /dev/null +++ b/dom/broadcastchannel/tests/browser_private_browsing.js @@ -0,0 +1,93 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +const URL = + "http://mochi.test:8888/browser/dom/broadcastchannel/tests/blank.html"; + +add_task(async function () { + var win1 = OpenBrowserWindow({ private: true }); + var win1Promise = new win1.Promise(resolve => { + win1.addEventListener( + "load", + function () { + resolve(); + }, + { once: true } + ); + }); + await win1Promise; + + var win2 = OpenBrowserWindow({ private: false }); + var win2Promise = new win2.Promise(resolve => { + win2.addEventListener( + "load", + function () { + resolve(); + }, + { once: true } + ); + }); + await win2Promise; + + var tab1 = BrowserTestUtils.addTab(win1.gBrowser, URL); + await BrowserTestUtils.browserLoaded(win1.gBrowser.getBrowserForTab(tab1)); + var browser1 = gBrowser.getBrowserForTab(tab1); + + var tab2 = BrowserTestUtils.addTab(win2.gBrowser, URL); + await BrowserTestUtils.browserLoaded(win2.gBrowser.getBrowserForTab(tab2)); + var browser2 = gBrowser.getBrowserForTab(tab2); + + var p1 = SpecialPowers.spawn(browser1, [], function (opts) { + return new content.window.Promise(resolve => { + content.window.bc = new content.window.BroadcastChannel("foobar"); + content.window.bc.onmessage = function (e) { + resolve(e.data); + }; + }); + }); + + var p2 = SpecialPowers.spawn(browser2, [], function (opts) { + return new content.window.Promise(resolve => { + content.window.bc = new content.window.BroadcastChannel("foobar"); + content.window.bc.onmessage = function (e) { + resolve(e.data); + }; + }); + }); + + await SpecialPowers.spawn(browser1, [], function (opts) { + return new content.window.Promise(resolve => { + var bc = new content.window.BroadcastChannel("foobar"); + bc.postMessage("hello world from private browsing"); + resolve(); + }); + }); + + await SpecialPowers.spawn(browser2, [], function (opts) { + return new content.window.Promise(resolve => { + var bc = new content.window.BroadcastChannel("foobar"); + bc.postMessage("hello world from non private browsing"); + resolve(); + }); + }); + + var what1 = await p1; + is( + what1, + "hello world from private browsing", + "No messages received from the other window." + ); + + var what2 = await p2; + is( + what2, + "hello world from non private browsing", + "No messages received from the other window." + ); + + BrowserTestUtils.removeTab(tab1); + await BrowserTestUtils.closeWindow(win1); + + BrowserTestUtils.removeTab(tab2); + await BrowserTestUtils.closeWindow(win2); +}); diff --git a/dom/broadcastchannel/tests/file_mozbrowser.html b/dom/broadcastchannel/tests/file_mozbrowser.html new file mode 100644 index 0000000000..6370500d98 --- /dev/null +++ b/dom/broadcastchannel/tests/file_mozbrowser.html @@ -0,0 +1,20 @@ + + + + + MozBrowser iframe + + +
+ + + diff --git a/dom/broadcastchannel/tests/file_mozbrowser2.html b/dom/broadcastchannel/tests/file_mozbrowser2.html new file mode 100644 index 0000000000..2e5f394eb8 --- /dev/null +++ b/dom/broadcastchannel/tests/file_mozbrowser2.html @@ -0,0 +1,21 @@ + + + + + MozBrowser iframe + + +
+ + + diff --git a/dom/broadcastchannel/tests/iframe_broadcastchannel.html b/dom/broadcastchannel/tests/iframe_broadcastchannel.html new file mode 100644 index 0000000000..2d1724da0b --- /dev/null +++ b/dom/broadcastchannel/tests/iframe_broadcastchannel.html @@ -0,0 +1,33 @@ + + + + + + diff --git a/dom/broadcastchannel/tests/iframe_mozbrowser.html b/dom/broadcastchannel/tests/iframe_mozbrowser.html new file mode 100644 index 0000000000..adbb77a061 --- /dev/null +++ b/dom/broadcastchannel/tests/iframe_mozbrowser.html @@ -0,0 +1,15 @@ + + + + + MozBrowser iframe + + + + + diff --git a/dom/broadcastchannel/tests/iframe_mozbrowser2.html b/dom/broadcastchannel/tests/iframe_mozbrowser2.html new file mode 100644 index 0000000000..adbb77a061 --- /dev/null +++ b/dom/broadcastchannel/tests/iframe_mozbrowser2.html @@ -0,0 +1,15 @@ + + + + + MozBrowser iframe + + + + + diff --git a/dom/broadcastchannel/tests/mochitest.toml b/dom/broadcastchannel/tests/mochitest.toml new file mode 100644 index 0000000000..40264f7a3d --- /dev/null +++ b/dom/broadcastchannel/tests/mochitest.toml @@ -0,0 +1,41 @@ +[DEFAULT] +support-files = [ + "iframe_broadcastchannel.html", + "broadcastchannel_sharedWorker.js", + "broadcastchannel_worker_alive.js", + "!/dom/events/test/event_leak_utils.js", + "file_mozbrowser.html", + "file_mozbrowser2.html", + "iframe_mozbrowser.html", + "iframe_mozbrowser2.html", + "testUrl1_bfcache.html", + "testUrl2_bfcache.html", +] + +["test_bfcache.html"] + +["test_broadcastchannel_basic.html"] +skip-if = [ + "http3", + "http2", +] + +["test_broadcastchannel_close.html"] + +["test_broadcastchannel_self.html"] + +["test_broadcastchannel_sharedWorker.html"] + +["test_broadcastchannel_worker_alive.html"] + +["test_dataCloning.html"] + +["test_dataURL.html"] + +["test_event_listener_leaks.html"] + +["test_invalidState.html"] + +["test_message_after_close.html"] + +["test_ordering.html"] diff --git a/dom/broadcastchannel/tests/testUrl1_bfcache.html b/dom/broadcastchannel/tests/testUrl1_bfcache.html new file mode 100644 index 0000000000..d31b13bd25 --- /dev/null +++ b/dom/broadcastchannel/tests/testUrl1_bfcache.html @@ -0,0 +1,18 @@ + diff --git a/dom/broadcastchannel/tests/testUrl2_bfcache.html b/dom/broadcastchannel/tests/testUrl2_bfcache.html new file mode 100644 index 0000000000..a1eed7927a --- /dev/null +++ b/dom/broadcastchannel/tests/testUrl2_bfcache.html @@ -0,0 +1,12 @@ + diff --git a/dom/broadcastchannel/tests/test_bfcache.html b/dom/broadcastchannel/tests/test_bfcache.html new file mode 100644 index 0000000000..0197f343e2 --- /dev/null +++ b/dom/broadcastchannel/tests/test_bfcache.html @@ -0,0 +1,120 @@ + + + + + Test for bfcache and BroadcastChannel + + + + + + + diff --git a/dom/broadcastchannel/tests/test_broadcastchannel_basic.html b/dom/broadcastchannel/tests/test_broadcastchannel_basic.html new file mode 100644 index 0000000000..09196b0c52 --- /dev/null +++ b/dom/broadcastchannel/tests/test_broadcastchannel_basic.html @@ -0,0 +1,67 @@ + + + + Test for BroadcastChannel + + + + + +
+ + + + diff --git a/dom/broadcastchannel/tests/test_broadcastchannel_close.html b/dom/broadcastchannel/tests/test_broadcastchannel_close.html new file mode 100644 index 0000000000..91cb9c92a4 --- /dev/null +++ b/dom/broadcastchannel/tests/test_broadcastchannel_close.html @@ -0,0 +1,61 @@ + + + + Test for BroadcastChannel + + + + + +
+ + + + diff --git a/dom/broadcastchannel/tests/test_broadcastchannel_self.html b/dom/broadcastchannel/tests/test_broadcastchannel_self.html new file mode 100644 index 0000000000..501f71f09c --- /dev/null +++ b/dom/broadcastchannel/tests/test_broadcastchannel_self.html @@ -0,0 +1,37 @@ + + + + Test for BroadcastChannel + + + + + +
+ + + + diff --git a/dom/broadcastchannel/tests/test_broadcastchannel_sharedWorker.html b/dom/broadcastchannel/tests/test_broadcastchannel_sharedWorker.html new file mode 100644 index 0000000000..f76c17cbd8 --- /dev/null +++ b/dom/broadcastchannel/tests/test_broadcastchannel_sharedWorker.html @@ -0,0 +1,52 @@ + + + + + + Test for BroadcastChannel in SharedWorkers + + + + +

+ +
+
+
+ + diff --git a/dom/broadcastchannel/tests/test_broadcastchannel_worker_alive.html b/dom/broadcastchannel/tests/test_broadcastchannel_worker_alive.html new file mode 100644 index 0000000000..3667c8ae9d --- /dev/null +++ b/dom/broadcastchannel/tests/test_broadcastchannel_worker_alive.html @@ -0,0 +1,56 @@ + + + + + + Test for BroadcastChannel in workers + + + + +

+ +
+
+
+ + diff --git a/dom/broadcastchannel/tests/test_dataCloning.html b/dom/broadcastchannel/tests/test_dataCloning.html new file mode 100644 index 0000000000..26c1ce370a --- /dev/null +++ b/dom/broadcastchannel/tests/test_dataCloning.html @@ -0,0 +1,27 @@ + + + + Test for BroadcastChannel.postMessage invalid State + + + + + +
+ + + + diff --git a/dom/broadcastchannel/tests/test_dataURL.html b/dom/broadcastchannel/tests/test_dataURL.html new file mode 100644 index 0000000000..f4f9c71db3 --- /dev/null +++ b/dom/broadcastchannel/tests/test_dataURL.html @@ -0,0 +1,35 @@ + + + + Test for BroadcastChannel in data: URL + + + + +
+var a = new BroadcastChannel('a'); +var b = new BroadcastChannel('a'); +a.onmessage = function(e) { parent.postMessage(e.data, "*"); }; +b.postMessage(42); +
+ + + + diff --git a/dom/broadcastchannel/tests/test_event_listener_leaks.html b/dom/broadcastchannel/tests/test_event_listener_leaks.html new file mode 100644 index 0000000000..33568913fc --- /dev/null +++ b/dom/broadcastchannel/tests/test_event_listener_leaks.html @@ -0,0 +1,55 @@ + + + + + Bug 1450358 - Test BroadcastChannel event listener leak conditions + + + + + + + + + diff --git a/dom/broadcastchannel/tests/test_invalidState.html b/dom/broadcastchannel/tests/test_invalidState.html new file mode 100644 index 0000000000..371a58768a --- /dev/null +++ b/dom/broadcastchannel/tests/test_invalidState.html @@ -0,0 +1,27 @@ + + + + Test for BroadcastChannel.postMessage invalid State + + + + + +
+ + + + diff --git a/dom/broadcastchannel/tests/test_message_after_close.html b/dom/broadcastchannel/tests/test_message_after_close.html new file mode 100644 index 0000000000..1ef8a018ea --- /dev/null +++ b/dom/broadcastchannel/tests/test_message_after_close.html @@ -0,0 +1,31 @@ + + + + Test for BroadcastChannel - message after close + + + + + + + diff --git a/dom/broadcastchannel/tests/test_ordering.html b/dom/broadcastchannel/tests/test_ordering.html new file mode 100644 index 0000000000..5dd36bc77d --- /dev/null +++ b/dom/broadcastchannel/tests/test_ordering.html @@ -0,0 +1,64 @@ + + + + Test for BroadcastChannel.postMessage invalid State + + + + + +
+ + + + -- cgit v1.2.3