From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- dom/broadcastchannel/BroadcastChannel.cpp | 685 +++++++++++++++++++++ dom/broadcastchannel/BroadcastChannel.h | 134 ++++ dom/broadcastchannel/BroadcastChannelChild.cpp | 135 ++++ dom/broadcastchannel/BroadcastChannelChild.h | 59 ++ dom/broadcastchannel/BroadcastChannelParent.cpp | 102 +++ dom/broadcastchannel/BroadcastChannelParent.h | 50 ++ dom/broadcastchannel/BroadcastChannelService.cpp | 132 ++++ dom/broadcastchannel/BroadcastChannelService.h | 52 ++ dom/broadcastchannel/PBroadcastChannel.ipdl | 29 + dom/broadcastchannel/moz.build | 31 + dom/broadcastchannel/tests/blank.html | 2 + .../tests/broadcastchannel_sharedWorker.js | 12 + .../tests/broadcastchannel_worker.js | 18 + .../tests/broadcastchannel_worker_alive.js | 8 + .../tests/broadcastchannel_worker_any.js | 5 + dom/broadcastchannel/tests/browser.ini | 6 + .../tests/browser_private_browsing.js | 74 +++ dom/broadcastchannel/tests/file_mozbrowser.html | 20 + dom/broadcastchannel/tests/file_mozbrowser2.html | 21 + .../tests/iframe_broadcastchannel.html | 35 ++ dom/broadcastchannel/tests/iframe_mozbrowser.html | 15 + dom/broadcastchannel/tests/iframe_mozbrowser2.html | 15 + dom/broadcastchannel/tests/mochitest.ini | 24 + dom/broadcastchannel/tests/test_bfcache.html | 96 +++ .../tests/test_broadcastchannel_any.html | 138 +++++ .../tests/test_broadcastchannel_basic.html | 68 ++ .../tests/test_broadcastchannel_close.html | 61 ++ .../tests/test_broadcastchannel_close2.html | 39 ++ .../tests/test_broadcastchannel_self.html | 38 ++ .../tests/test_broadcastchannel_sharedWorker.html | 52 ++ .../tests/test_broadcastchannel_worker.html | 62 ++ .../tests/test_broadcastchannel_worker_alive.html | 56 ++ dom/broadcastchannel/tests/test_dataCloning.html | 27 + dom/broadcastchannel/tests/test_invalidState.html | 28 + dom/broadcastchannel/tests/test_ordering.html | 65 ++ 35 files changed, 2394 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.js create mode 100644 dom/broadcastchannel/tests/broadcastchannel_worker_alive.js create mode 100644 dom/broadcastchannel/tests/broadcastchannel_worker_any.js create mode 100644 dom/broadcastchannel/tests/browser.ini 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.ini create mode 100644 dom/broadcastchannel/tests/test_bfcache.html create mode 100644 dom/broadcastchannel/tests/test_broadcastchannel_any.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_close2.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.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_invalidState.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 000000000..c3c2d448b --- /dev/null +++ b/dom/broadcastchannel/BroadcastChannel.cpp @@ -0,0 +1,685 @@ +/* -*- 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/StructuredCloneHolder.h" +#include "mozilla/ipc/BackgroundChild.h" +#include "mozilla/ipc/BackgroundUtils.h" +#include "mozilla/ipc/PBackgroundChild.h" +#include "nsContentUtils.h" +#include "WorkerPrivate.h" +#include "WorkerRunnable.h" + +#include "nsIBFCacheEntry.h" +#include "nsIDocument.h" +#include "nsISupportsPrimitives.h" + +#ifdef XP_WIN +#undef PostMessage +#endif + +namespace mozilla { + +using namespace ipc; + +namespace dom { + +using namespace workers; + +class BroadcastChannelMessage final : public StructuredCloneHolder +{ +public: + NS_INLINE_DECL_REFCOUNTING(BroadcastChannelMessage) + + BroadcastChannelMessage() + : StructuredCloneHolder(CloningSupported, TransferringNotSupported, + StructuredCloneScope::DifferentProcess) + {} + +private: + ~BroadcastChannelMessage() + {} +}; + +namespace { + +nsIPrincipal* +GetPrincipalFromWorkerPrivate(WorkerPrivate* aWorkerPrivate) +{ + nsIPrincipal* principal = aWorkerPrivate->GetPrincipal(); + if (principal) { + return principal; + } + + // Walk up to our containing page + WorkerPrivate* wp = aWorkerPrivate; + while (wp->GetParent()) { + wp = wp->GetParent(); + } + + return wp->GetPrincipal(); +} + +class InitializeRunnable final : public WorkerMainThreadRunnable +{ +public: + InitializeRunnable(WorkerPrivate* aWorkerPrivate, nsACString& aOrigin, + PrincipalInfo& aPrincipalInfo, ErrorResult& aRv) + : WorkerMainThreadRunnable(aWorkerPrivate, + NS_LITERAL_CSTRING("BroadcastChannel :: Initialize")) + , mWorkerPrivate(GetCurrentThreadWorkerPrivate()) + , mOrigin(aOrigin) + , mPrincipalInfo(aPrincipalInfo) + , mRv(aRv) + { + MOZ_ASSERT(mWorkerPrivate); + } + + bool MainThreadRun() override + { + MOZ_ASSERT(NS_IsMainThread()); + + nsIPrincipal* principal = GetPrincipalFromWorkerPrivate(mWorkerPrivate); + if (!principal) { + mRv.Throw(NS_ERROR_FAILURE); + return true; + } + + if (NS_WARN_IF(principal->GetIsNullPrincipal())) { + mRv.Throw(NS_ERROR_FAILURE); + return true; + } + + mRv = PrincipalToPrincipalInfo(principal, &mPrincipalInfo); + if (NS_WARN_IF(mRv.Failed())) { + return true; + } + + mRv = principal->GetOrigin(mOrigin); + if (NS_WARN_IF(mRv.Failed())) { + return true; + } + + // Walk up to our containing page + WorkerPrivate* wp = mWorkerPrivate; + while (wp->GetParent()) { + wp = wp->GetParent(); + } + + // Window doesn't exist for some kind of workers (eg: SharedWorkers) + nsPIDOMWindowInner* window = wp->GetWindow(); + if (!window) { + return true; + } + + return true; + } + +private: + WorkerPrivate* mWorkerPrivate; + nsACString& mOrigin; + PrincipalInfo& mPrincipalInfo; + ErrorResult& mRv; +}; + +class BCPostMessageRunnable final : public nsIRunnable, + public nsICancelableRunnable +{ +public: + NS_DECL_ISUPPORTS + + BCPostMessageRunnable(BroadcastChannelChild* aActor, + BroadcastChannelMessage* aData) + : mActor(aActor) + , mData(aData) + { + MOZ_ASSERT(mActor); + } + + NS_IMETHOD Run() override + { + MOZ_ASSERT(mActor); + if (mActor->IsActorDestroyed()) { + return NS_OK; + } + + ClonedMessageData message; + + bool success; + SerializedStructuredCloneBuffer& buffer = message.data(); + auto iter = mData->BufferData().Iter(); + buffer.data = mData->BufferData().Borrow(iter, mData->BufferData().Size(), &success); + if (NS_WARN_IF(!success)) { + return NS_OK; + } + + PBackgroundChild* backgroundManager = mActor->Manager(); + MOZ_ASSERT(backgroundManager); + + const nsTArray>& blobImpls = mData->BlobImpls(); + + if (!blobImpls.IsEmpty()) { + message.blobsChild().SetCapacity(blobImpls.Length()); + + for (uint32_t i = 0, len = blobImpls.Length(); i < len; ++i) { + PBlobChild* blobChild = + BackgroundChild::GetOrCreateActorForBlobImpl(backgroundManager, + blobImpls[i]); + MOZ_ASSERT(blobChild); + + message.blobsChild().AppendElement(blobChild); + } + } + + mActor->SendPostMessage(message); + return NS_OK; + } + + nsresult Cancel() override + { + mActor = nullptr; + return NS_OK; + } + +private: + ~BCPostMessageRunnable() {} + + RefPtr mActor; + RefPtr mData; +}; + +NS_IMPL_ISUPPORTS(BCPostMessageRunnable, nsICancelableRunnable, nsIRunnable) + +class CloseRunnable final : public nsIRunnable, + public nsICancelableRunnable +{ +public: + NS_DECL_ISUPPORTS + + explicit CloseRunnable(BroadcastChannel* aBC) + : mBC(aBC) + { + MOZ_ASSERT(mBC); + } + + NS_IMETHOD Run() override + { + mBC->Shutdown(); + return NS_OK; + } + + nsresult Cancel() override + { + mBC = nullptr; + return NS_OK; + } + +private: + ~CloseRunnable() {} + + RefPtr mBC; +}; + +NS_IMPL_ISUPPORTS(CloseRunnable, nsICancelableRunnable, nsIRunnable) + +class TeardownRunnable final : public nsIRunnable, + public nsICancelableRunnable +{ +public: + NS_DECL_ISUPPORTS + + explicit TeardownRunnable(BroadcastChannelChild* aActor) + : mActor(aActor) + { + MOZ_ASSERT(mActor); + } + + NS_IMETHOD Run() override + { + MOZ_ASSERT(mActor); + if (!mActor->IsActorDestroyed()) { + mActor->SendClose(); + } + return NS_OK; + } + + nsresult Cancel() override + { + mActor = nullptr; + return NS_OK; + } + +private: + ~TeardownRunnable() {} + + RefPtr mActor; +}; + +NS_IMPL_ISUPPORTS(TeardownRunnable, nsICancelableRunnable, nsIRunnable) + +class BroadcastChannelWorkerHolder final : public workers::WorkerHolder +{ + BroadcastChannel* mChannel; + +public: + explicit BroadcastChannelWorkerHolder(BroadcastChannel* aChannel) + : mChannel(aChannel) + { + MOZ_COUNT_CTOR(BroadcastChannelWorkerHolder); + } + + virtual bool Notify(workers::Status aStatus) override + { + if (aStatus >= Closing) { + mChannel->Shutdown(); + } + + return true; + } + +private: + ~BroadcastChannelWorkerHolder() + { + MOZ_COUNT_DTOR(BroadcastChannelWorkerHolder); + } +}; + +} // namespace + +BroadcastChannel::BroadcastChannel(nsPIDOMWindowInner* aWindow, + const PrincipalInfo& aPrincipalInfo, + const nsACString& aOrigin, + const nsAString& aChannel) + : DOMEventTargetHelper(aWindow) + , mWorkerHolder(nullptr) + , mPrincipalInfo(new PrincipalInfo(aPrincipalInfo)) + , mOrigin(aOrigin) + , mChannel(aChannel) + , mIsKeptAlive(false) + , mInnerID(0) + , mState(StateActive) +{ + // Window can be null in workers +} + +BroadcastChannel::~BroadcastChannel() +{ + Shutdown(); + MOZ_ASSERT(!mWorkerHolder); +} + +JSObject* +BroadcastChannel::WrapObject(JSContext* aCx, JS::Handle aGivenProto) +{ + return BroadcastChannelBinding::Wrap(aCx, this, aGivenProto); +} + +/* static */ already_AddRefed +BroadcastChannel::Constructor(const GlobalObject& aGlobal, + const nsAString& aChannel, + ErrorResult& aRv) +{ + nsCOMPtr window = + do_QueryInterface(aGlobal.GetAsSupports()); + // Window is null in workers. + + nsAutoCString origin; + PrincipalInfo principalInfo; + WorkerPrivate* workerPrivate = nullptr; + + if (NS_IsMainThread()) { + nsCOMPtr incumbent = mozilla::dom::GetIncumbentGlobal(); + + if (!incumbent) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + nsIPrincipal* principal = incumbent->PrincipalOrNull(); + if (!principal) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } + + if (NS_WARN_IF(principal->GetIsNullPrincipal())) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + aRv = principal->GetOrigin(origin); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + aRv = PrincipalToPrincipalInfo(principal, &principalInfo); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + } else { + JSContext* cx = aGlobal.Context(); + workerPrivate = GetWorkerPrivateFromContext(cx); + MOZ_ASSERT(workerPrivate); + + RefPtr runnable = + new InitializeRunnable(workerPrivate, origin, principalInfo, aRv); + runnable->Dispatch(aRv); + } + + if (aRv.Failed()) { + return nullptr; + } + + RefPtr bc = + new BroadcastChannel(window, principalInfo, origin, aChannel); + + // Register this component to PBackground. + PBackgroundChild* actor = BackgroundChild::GetForCurrentThread(); + if (actor) { + bc->ActorCreated(actor); + } else { + BackgroundChild::GetOrCreateForCurrentThread(bc); + } + + if (!workerPrivate) { + MOZ_ASSERT(window); + MOZ_ASSERT(window->IsInnerWindow()); + bc->mInnerID = window->WindowID(); + + // Register as observer for inner-window-destroyed. + nsCOMPtr obs = mozilla::services::GetObserverService(); + if (obs) { + obs->AddObserver(bc, "inner-window-destroyed", false); + } + } else { + bc->mWorkerHolder = new BroadcastChannelWorkerHolder(bc); + if (NS_WARN_IF(!bc->mWorkerHolder->HoldWorker(workerPrivate, Closing))) { + bc->mWorkerHolder = nullptr; + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + } + + 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; + } + + PostMessageInternal(aCx, aMessage, aRv); +} + +void +BroadcastChannel::PostMessageInternal(JSContext* aCx, + JS::Handle aMessage, + ErrorResult& aRv) +{ + RefPtr data = new BroadcastChannelMessage(); + + data->Write(aCx, aMessage, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + + PostMessageData(data); +} + +void +BroadcastChannel::PostMessageData(BroadcastChannelMessage* aData) +{ + RemoveDocFromBFCache(); + + if (mActor) { + RefPtr runnable = + new BCPostMessageRunnable(mActor, aData); + + if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) { + NS_WARNING("Failed to dispatch to the current thread!"); + } + + return; + } + + mPendingMessages.AppendElement(aData); +} + +void +BroadcastChannel::Close() +{ + if (mState != StateActive) { + return; + } + + if (mPendingMessages.IsEmpty()) { + // 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!"); + } + } else { + MOZ_ASSERT(!mActor); + mState = StateClosing; + } +} + +void +BroadcastChannel::ActorFailed() +{ + MOZ_CRASH("Failed to create a PBackgroundChild actor!"); +} + +void +BroadcastChannel::ActorCreated(PBackgroundChild* aActor) +{ + MOZ_ASSERT(aActor); + + if (mState == StateClosed) { + return; + } + + PBroadcastChannelChild* actor = + aActor->SendPBroadcastChannelConstructor(*mPrincipalInfo, mOrigin, mChannel); + + mActor = static_cast(actor); + MOZ_ASSERT(mActor); + + mActor->SetParent(this); + + // Flush pending messages. + for (uint32_t i = 0; i < mPendingMessages.Length(); ++i) { + PostMessageData(mPendingMessages[i]); + } + + mPendingMessages.Clear(); + + if (mState == StateClosing) { + Shutdown(); + } +} + +void +BroadcastChannel::Shutdown() +{ + mState = StateClosed; + + // The DTOR of this WorkerHolder will release the worker for us. + mWorkerHolder = nullptr; + + if (mActor) { + mActor->SetParent(nullptr); + + RefPtr runnable = new TeardownRunnable(mActor); + NS_DispatchToCurrentThread(runnable); + + mActor = nullptr; + } + + // If shutdown() is called we have to release the reference if we still keep + // it. + if (mIsKeptAlive) { + mIsKeptAlive = false; + Release(); + } +} + +EventHandlerNonNull* +BroadcastChannel::GetOnmessage() +{ + if (NS_IsMainThread()) { + return GetEventHandler(nsGkAtoms::onmessage, EmptyString()); + } + return GetEventHandler(nullptr, NS_LITERAL_STRING("message")); +} + +void +BroadcastChannel::SetOnmessage(EventHandlerNonNull* aCallback) +{ + if (NS_IsMainThread()) { + SetEventHandler(nsGkAtoms::onmessage, EmptyString(), aCallback); + } else { + SetEventHandler(nullptr, NS_LITERAL_STRING("message"), aCallback); + } + + UpdateMustKeepAlive(); +} + +void +BroadcastChannel::AddEventListener(const nsAString& aType, + EventListener* aCallback, + const AddEventListenerOptionsOrBoolean& aOptions, + const dom::Nullable& aWantsUntrusted, + ErrorResult& aRv) +{ + DOMEventTargetHelper::AddEventListener(aType, aCallback, aOptions, + aWantsUntrusted, aRv); + + if (aRv.Failed()) { + return; + } + + UpdateMustKeepAlive(); +} + +void +BroadcastChannel::RemoveEventListener(const nsAString& aType, + EventListener* aCallback, + const EventListenerOptionsOrBoolean& aOptions, + ErrorResult& aRv) +{ + DOMEventTargetHelper::RemoveEventListener(aType, aCallback, aOptions, aRv); + + if (aRv.Failed()) { + return; + } + + UpdateMustKeepAlive(); +} + +void +BroadcastChannel::UpdateMustKeepAlive() +{ + bool toKeepAlive = HasListenersFor(NS_LITERAL_STRING("message")); + if (toKeepAlive == mIsKeptAlive) { + return; + } + + mIsKeptAlive = toKeepAlive; + + if (toKeepAlive) { + AddRef(); + } else { + Release(); + } +} + +NS_IMETHODIMP +BroadcastChannel::Observe(nsISupports* aSubject, const char* aTopic, + const char16_t* aData) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(!strcmp(aTopic, "inner-window-destroyed")); + + // If the window is destroyed we have to release the reference that we are + // keeping. + nsCOMPtr wrapper = do_QueryInterface(aSubject); + NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE); + + uint64_t innerID; + nsresult rv = wrapper->GetData(&innerID); + NS_ENSURE_SUCCESS(rv, rv); + + if (innerID == mInnerID) { + nsCOMPtr obs = mozilla::services::GetObserverService(); + if (obs) { + obs->RemoveObserver(this, "inner-window-destroyed"); + } + + Shutdown(); + } + + return NS_OK; +} + +void +BroadcastChannel::RemoveDocFromBFCache() +{ + if (!NS_IsMainThread()) { + return; + } + + nsPIDOMWindowInner* window = GetOwner(); + if (!window) { + return; + } + + nsIDocument* doc = window->GetExtantDoc(); + if (!doc) { + return; + } + + nsCOMPtr bfCacheEntry = doc->GetBFCacheEntry(); + if (!bfCacheEntry) { + return; + } + + bfCacheEntry->RemoveFromBFCacheSync(); +} + +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_INHERITED(BroadcastChannel) + NS_INTERFACE_MAP_ENTRY(nsIIPCBackgroundChildCreateCallback) + NS_INTERFACE_MAP_ENTRY(nsIObserver) +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 000000000..d7d46eeec --- /dev/null +++ b/dom/broadcastchannel/BroadcastChannel.h @@ -0,0 +1,134 @@ +/* -*- 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 "nsAutoPtr.h" +#include "nsIIPCBackgroundChildCreateCallback.h" +#include "nsIObserver.h" +#include "nsTArray.h" +#include "mozilla/RefPtr.h" + +class nsPIDOMWindowInner; + +namespace mozilla { + +namespace ipc { +class PrincipalInfo; +} // namespace ipc + +namespace dom { + +namespace workers { +class WorkerHolder; +} // namespace workers + +class BroadcastChannelChild; +class BroadcastChannelMessage; + +class BroadcastChannel final + : public DOMEventTargetHelper + , public nsIIPCBackgroundChildCreateCallback + , public nsIObserver +{ + friend class BroadcastChannelChild; + + NS_DECL_NSIIPCBACKGROUNDCHILDCREATECALLBACK + NS_DECL_NSIOBSERVER + + typedef mozilla::ipc::PrincipalInfo 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(); + + EventHandlerNonNull* GetOnmessage(); + void SetOnmessage(EventHandlerNonNull* aCallback); + + using nsIDOMEventTarget::AddEventListener; + using nsIDOMEventTarget::RemoveEventListener; + + virtual void AddEventListener(const nsAString& aType, + EventListener* aCallback, + const AddEventListenerOptionsOrBoolean& aOptions, + const Nullable& aWantsUntrusted, + ErrorResult& aRv) override; + virtual void RemoveEventListener(const nsAString& aType, + EventListener* aCallback, + const EventListenerOptionsOrBoolean& aOptions, + ErrorResult& aRv) override; + + void Shutdown(); + +private: + BroadcastChannel(nsPIDOMWindowInner* aWindow, + const PrincipalInfo& aPrincipalInfo, + const nsACString& aOrigin, + const nsAString& aChannel); + + ~BroadcastChannel(); + + void PostMessageData(BroadcastChannelMessage* aData); + + void PostMessageInternal(JSContext* aCx, JS::Handle aMessage, + ErrorResult& aRv); + + void UpdateMustKeepAlive(); + + bool IsCertainlyAliveForCC() const override + { + return mIsKeptAlive; + } + + void RemoveDocFromBFCache(); + + RefPtr mActor; + nsTArray> mPendingMessages; + + nsAutoPtr mWorkerHolder; + + nsAutoPtr mPrincipalInfo; + + nsCString mOrigin; + nsString mChannel; + + bool mIsKeptAlive; + + uint64_t mInnerID; + + enum { + StateActive, + StateClosing, + StateClosed + } mState; +}; + +} // 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 000000000..98bd21999 --- /dev/null +++ b/dom/broadcastchannel/BroadcastChannelChild.cpp @@ -0,0 +1,135 @@ +/* -*- 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" +#include "jsapi.h" +#include "mozilla/dom/ipc/BlobChild.h" +#include "mozilla/dom/File.h" +#include "mozilla/dom/MessageEvent.h" +#include "mozilla/dom/MessageEventBinding.h" +#include "mozilla/dom/WorkerPrivate.h" +#include "mozilla/dom/WorkerScope.h" +#include "mozilla/dom/ScriptSettings.h" +#include "mozilla/ipc/PBackgroundChild.h" +#include "mozilla/dom/ipc/StructuredCloneData.h" +#include "WorkerPrivate.h" + +namespace mozilla { + +using namespace ipc; + +namespace dom { + +using namespace workers; + +BroadcastChannelChild::BroadcastChannelChild(const nsACString& aOrigin) + : mBC(nullptr) + , mActorDestroyed(false) +{ + CopyUTF8toUTF16(aOrigin, mOrigin); +} + +BroadcastChannelChild::~BroadcastChannelChild() +{ + MOZ_ASSERT(!mBC); +} + +bool +BroadcastChannelChild::RecvNotify(const ClonedMessageData& aData) +{ + // Make sure to retrieve all blobs from the message before returning to avoid + // leaking their actors. + nsTArray> blobs; + if (!aData.blobsChild().IsEmpty()) { + blobs.SetCapacity(aData.blobsChild().Length()); + + for (uint32_t i = 0, len = aData.blobsChild().Length(); i < len; ++i) { + RefPtr impl = + static_cast(aData.blobsChild()[i])->GetBlobImpl(); + + blobs.AppendElement(impl); + } + } + + nsCOMPtr helper = mBC; + nsCOMPtr eventTarget = do_QueryInterface(helper); + + // The object is going to be deleted soon. No notify is required. + if (!eventTarget) { + return true; + } + + // CheckInnerWindowCorrectness can be used also without a window when + // BroadcastChannel is running in a worker. In this case, it's a NOP. + if (NS_FAILED(mBC->CheckInnerWindowCorrectness())) { + return true; + } + + mBC->RemoveDocFromBFCache(); + + AutoJSAPI jsapi; + nsCOMPtr globalObject; + + if (NS_IsMainThread()) { + globalObject = do_QueryInterface(mBC->GetParentObject()); + } else { + WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); + MOZ_ASSERT(workerPrivate); + globalObject = workerPrivate->GlobalScope(); + } + + if (!globalObject || !jsapi.Init(globalObject)) { + NS_WARNING("Failed to initialize AutoJSAPI object."); + return true; + } + + ipc::StructuredCloneData cloneData; + cloneData.BlobImpls().AppendElements(blobs); + + const SerializedStructuredCloneBuffer& buffer = aData.data(); + JSContext* cx = jsapi.cx(); + JS::Rooted value(cx, JS::NullValue()); + if (buffer.data.Size()) { + ErrorResult rv; + cloneData.UseExternalData(buffer.data); + cloneData.Read(cx, &value, rv); + if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); + return true; + } + } + + RootedDictionary init(cx); + init.mBubbles = false; + init.mCancelable = false; + init.mOrigin = mOrigin; + init.mData = value; + + ErrorResult rv; + RefPtr event = + MessageEvent::Constructor(mBC, NS_LITERAL_STRING("message"), init, rv); + if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); + return true; + } + + event->SetTrusted(true); + + bool status; + mBC->DispatchEvent(static_cast(event.get()), &status); + + return true; +} + +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 000000000..23cef899e --- /dev/null +++ b/dom/broadcastchannel/BroadcastChannelChild.h @@ -0,0 +1,59 @@ +/* -*- 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 bool RecvNotify(const ClonedMessageData& aData) override; + + bool IsActorDestroyed() const + { + return mActorDestroyed; + } + +private: + explicit BroadcastChannelChild(const nsACString& aOrigin); + ~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; + + nsString mOrigin; + + 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 000000000..f26292e1d --- /dev/null +++ b/dom/broadcastchannel/BroadcastChannelParent.cpp @@ -0,0 +1,102 @@ +/* -*- 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/ipc/BlobParent.h" +#include "mozilla/ipc/BackgroundParent.h" +#include "mozilla/Unused.h" +#include "nsIScriptSecurityManager.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(); +} + +bool +BroadcastChannelParent::RecvPostMessage(const ClonedMessageData& aData) +{ + AssertIsOnBackgroundThread(); + + if (NS_WARN_IF(!mService)) { + return false; + } + + mService->PostMessage(this, aData, mOriginChannelKey); + return true; +} + +bool +BroadcastChannelParent::RecvClose() +{ + AssertIsOnBackgroundThread(); + + if (NS_WARN_IF(!mService)) { + return false; + } + + mService->UnregisterActor(this, mOriginChannelKey); + mService = nullptr; + + Unused << Send__delete__(this); + + return true; +} + +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); + } +} + +void +BroadcastChannelParent::Deliver(const ClonedMessageData& aData) +{ + AssertIsOnBackgroundThread(); + + // Duplicate the data for this parent. + ClonedMessageData newData(aData); + + // Create new BlobParent objects for this message. + for (uint32_t i = 0, len = newData.blobsParent().Length(); i < len; ++i) { + RefPtr impl = + static_cast(newData.blobsParent()[i])->GetBlobImpl(); + + PBlobParent* blobParent = + BackgroundParent::GetOrCreateActorForBlobImpl(Manager(), impl); + if (!blobParent) { + return; + } + + newData.blobsParent()[i] = blobParent; + } + + Unused << SendNotify(newData); +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/broadcastchannel/BroadcastChannelParent.h b/dom/broadcastchannel/BroadcastChannelParent.h new file mode 100644 index 000000000..e71354ca7 --- /dev/null +++ b/dom/broadcastchannel/BroadcastChannelParent.h @@ -0,0 +1,50 @@ +/* -*- 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; + + typedef mozilla::ipc::PrincipalInfo PrincipalInfo; + +public: + void Deliver(const ClonedMessageData& aData); + +private: + explicit BroadcastChannelParent(const nsAString& aOriginChannelKey); + ~BroadcastChannelParent(); + + virtual bool + RecvPostMessage(const ClonedMessageData& aData) override; + + virtual bool 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 000000000..f88108c3a --- /dev/null +++ b/dom/broadcastchannel/BroadcastChannelService.cpp @@ -0,0 +1,132 @@ +/* -*- 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/File.h" +#include "mozilla/dom/ipc/BlobParent.h" +#include "mozilla/ipc/BackgroundParent.h" + +#ifdef XP_WIN +#undef PostMessage +#endif + +namespace mozilla { + +using namespace ipc; + +namespace dom { + +namespace { + +BroadcastChannelService* sInstance = nullptr; + +} // 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); + + nsTArray* parents; + if (!mAgents.Get(aOriginChannelKey, &parents)) { + parents = new nsTArray(); + mAgents.Put(aOriginChannelKey, parents); + } + + MOZ_ASSERT(!parents->Contains(aParent)); + parents->AppendElement(aParent); +} + +void +BroadcastChannelService::UnregisterActor(BroadcastChannelParent* aParent, + const nsAString& aOriginChannelKey) +{ + AssertIsOnBackgroundThread(); + MOZ_ASSERT(aParent); + + nsTArray* parents; + if (!mAgents.Get(aOriginChannelKey, &parents)) { + MOZ_CRASH("Invalid state"); + } + + parents->RemoveElement(aParent); + if (parents->IsEmpty()) { + mAgents.Remove(aOriginChannelKey); + } +} + +void +BroadcastChannelService::PostMessage(BroadcastChannelParent* aParent, + const ClonedMessageData& 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> blobs; + if (!aData.blobsParent().IsEmpty()) { + blobs.SetCapacity(aData.blobsParent().Length()); + + for (uint32_t i = 0, len = aData.blobsParent().Length(); i < len; ++i) { + RefPtr impl = + static_cast(aData.blobsParent()[i])->GetBlobImpl(); + MOZ_ASSERT(impl); + blobs.AppendElement(impl); + } + } + + for (uint32_t i = 0; i < parents->Length(); ++i) { + BroadcastChannelParent* parent = parents->ElementAt(i); + MOZ_ASSERT(parent); + + if (parent != aParent) { + parent->Deliver(aData); + } + } +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/broadcastchannel/BroadcastChannelService.h b/dom/broadcastchannel/BroadcastChannelService.h new file mode 100644 index 000000000..3934a7ebf --- /dev/null +++ b/dom/broadcastchannel/BroadcastChannelService.h @@ -0,0 +1,52 @@ +/* -*- 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 { +namespace dom { + +class BroadcastChannelParent; +class ClonedMessageData; + +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 ClonedMessageData& aData, + const nsAString& aOriginChannelKey); + +private: + BroadcastChannelService(); + ~BroadcastChannelService(); + + // Raw Pointers because the actors keep alive this service. + nsClassHashtable> mAgents; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_BroadcastChannelService_h diff --git a/dom/broadcastchannel/PBroadcastChannel.ipdl b/dom/broadcastchannel/PBroadcastChannel.ipdl new file mode 100644 index 000000000..4b4a53106 --- /dev/null +++ b/dom/broadcastchannel/PBroadcastChannel.ipdl @@ -0,0 +1,29 @@ +/* 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 protocol PBlob; +include DOMTypes; + +using struct mozilla::SerializedStructuredCloneBuffer from "ipc/IPCMessageUtils.h"; + +namespace mozilla { +namespace dom { + +// This protocol is used for the BroadcastChannel API +protocol PBroadcastChannel +{ + manager PBackground; + +parent: + async PostMessage(ClonedMessageData message); + async Close(); + +child: + async Notify(ClonedMessageData message); + async __delete__(); +}; + +} // namespace dom +} // namespace mozilla diff --git a/dom/broadcastchannel/moz.build b/dom/broadcastchannel/moz.build new file mode 100644 index 000000000..a076331e5 --- /dev/null +++ b/dom/broadcastchannel/moz.build @@ -0,0 +1,31 @@ +# -*- 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/. + +EXPORTS.mozilla.dom += [ + 'BroadcastChannel.h', +] + +UNIFIED_SOURCES += [ + 'BroadcastChannel.cpp', + 'BroadcastChannelChild.cpp', + 'BroadcastChannelParent.cpp', + 'BroadcastChannelService.cpp', +] + +IPDL_SOURCES += [ + 'PBroadcastChannel.ipdl', +] + +LOCAL_INCLUDES += [ + '../workers', +] + +MOCHITEST_MANIFESTS += ['tests/mochitest.ini'] +BROWSER_CHROME_MANIFESTS += ['tests/browser.ini'] + +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 000000000..358db717d --- /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 000000000..4dad5ae82 --- /dev/null +++ b/dom/broadcastchannel/tests/broadcastchannel_sharedWorker.js @@ -0,0 +1,12 @@ +onconnect = function(evt) { + evt.ports[0].onmessage = function(evt) { + 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(); + }, false); + + evt.target.postMessage("READY"); + } +} diff --git a/dom/broadcastchannel/tests/broadcastchannel_worker.js b/dom/broadcastchannel/tests/broadcastchannel_worker.js new file mode 100644 index 000000000..4714d59d0 --- /dev/null +++ b/dom/broadcastchannel/tests/broadcastchannel_worker.js @@ -0,0 +1,18 @@ +onmessage = function(evt) { + if (evt.data != 0) { + var worker = new Worker("broadcastchannel_worker.js"); + worker.onmessage = function(evt) { + postMessage(evt.data); + } + worker.postMessage(evt.data - 1); + return; + } + + 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(); + }, false); + + 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 000000000..78ab44015 --- /dev/null +++ b/dom/broadcastchannel/tests/broadcastchannel_worker_alive.js @@ -0,0 +1,8 @@ +(new BroadcastChannel('foobar')).postMessage('READY'); + +(new BroadcastChannel('foobar')).addEventListener('message', function(event) { + if (event.data != 'READY') { + event.target.postMessage(event.data); + } +}, false); + diff --git a/dom/broadcastchannel/tests/broadcastchannel_worker_any.js b/dom/broadcastchannel/tests/broadcastchannel_worker_any.js new file mode 100644 index 000000000..da8625c4d --- /dev/null +++ b/dom/broadcastchannel/tests/broadcastchannel_worker_any.js @@ -0,0 +1,5 @@ +(new BroadcastChannel('foobar')).onmessage = function(event) { + event.target.postMessage(event.data); +} + +postMessage("READY"); diff --git a/dom/broadcastchannel/tests/browser.ini b/dom/broadcastchannel/tests/browser.ini new file mode 100644 index 000000000..b036a1e9b --- /dev/null +++ b/dom/broadcastchannel/tests/browser.ini @@ -0,0 +1,6 @@ +[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 000000000..5724225fc --- /dev/null +++ b/dom/broadcastchannel/tests/browser_private_browsing.js @@ -0,0 +1,74 @@ +/* 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(function*() { + var win1 = OpenBrowserWindow({private: true}); + var win1Promise = new win1.Promise(resolve => { + win1.addEventListener("load", function onLoad() { + win1.removeEventListener("load", onLoad, false); + resolve(); + }); + }); + yield win1Promise; + + var win2 = OpenBrowserWindow({private: false}); + var win2Promise = new win2.Promise(resolve => { + win2.addEventListener("load", function onLoad() { + win2.removeEventListener("load", onLoad, false); + resolve(); + }); + }); + yield win2Promise; + + var tab1 = win1.gBrowser.addTab(URL); + yield BrowserTestUtils.browserLoaded(win1.gBrowser.getBrowserForTab(tab1)); + var browser1 = gBrowser.getBrowserForTab(tab1); + + var tab2 = win2.gBrowser.addTab(URL); + yield BrowserTestUtils.browserLoaded(win2.gBrowser.getBrowserForTab(tab2)); + var browser2 = gBrowser.getBrowserForTab(tab2); + + var p1 = ContentTask.spawn(browser1, null, 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 = ContentTask.spawn(browser2, null, 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); } + }); + }); + + yield ContentTask.spawn(browser1, null, function(opts) { + return new content.window.Promise(resolve => { + var bc = new content.window.BroadcastChannel('foobar'); + bc.postMessage('hello world from private browsing'); + resolve(); + }); + }); + + yield ContentTask.spawn(browser2, null, 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 = yield p1; + ok(what1, 'hello world from private browsing', 'No messages received from the other window.'); + + var what2 = yield p2; + ok(what1, 'hello world from non private browsing', 'No messages received from the other window.'); + + yield BrowserTestUtils.removeTab(tab1); + yield BrowserTestUtils.closeWindow(win1); + + yield BrowserTestUtils.removeTab(tab2); + yield BrowserTestUtils.closeWindow(win2); +}); diff --git a/dom/broadcastchannel/tests/file_mozbrowser.html b/dom/broadcastchannel/tests/file_mozbrowser.html new file mode 100644 index 000000000..5f6902132 --- /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 000000000..85abce7bf --- /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 000000000..fb9a12b4b --- /dev/null +++ b/dom/broadcastchannel/tests/iframe_broadcastchannel.html @@ -0,0 +1,35 @@ + + + + + + + + diff --git a/dom/broadcastchannel/tests/iframe_mozbrowser.html b/dom/broadcastchannel/tests/iframe_mozbrowser.html new file mode 100644 index 000000000..dbcf63d88 --- /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 000000000..dbcf63d88 --- /dev/null +++ b/dom/broadcastchannel/tests/iframe_mozbrowser2.html @@ -0,0 +1,15 @@ + + + + + MozBrowser iframe + + + + + diff --git a/dom/broadcastchannel/tests/mochitest.ini b/dom/broadcastchannel/tests/mochitest.ini new file mode 100644 index 000000000..6dff47db4 --- /dev/null +++ b/dom/broadcastchannel/tests/mochitest.ini @@ -0,0 +1,24 @@ +[DEFAULT] +support-files = + iframe_broadcastchannel.html + broadcastchannel_sharedWorker.js + broadcastchannel_worker.js + broadcastchannel_worker_alive.js + broadcastchannel_worker_any.js + file_mozbrowser.html + file_mozbrowser2.html + iframe_mozbrowser.html + iframe_mozbrowser2.html + +[test_broadcastchannel_any.html] +[test_broadcastchannel_basic.html] +[test_broadcastchannel_close.html] +[test_broadcastchannel_close2.html] +[test_broadcastchannel_self.html] +[test_broadcastchannel_sharedWorker.html] +[test_broadcastchannel_worker.html] +[test_broadcastchannel_worker_alive.html] +[test_bfcache.html] +[test_invalidState.html] +[test_ordering.html] +[test_dataCloning.html] diff --git a/dom/broadcastchannel/tests/test_bfcache.html b/dom/broadcastchannel/tests/test_bfcache.html new file mode 100644 index 000000000..e42496bac --- /dev/null +++ b/dom/broadcastchannel/tests/test_bfcache.html @@ -0,0 +1,96 @@ + + + + + Test for bfcache and BroadcastChannel + + + + + + + diff --git a/dom/broadcastchannel/tests/test_broadcastchannel_any.html b/dom/broadcastchannel/tests/test_broadcastchannel_any.html new file mode 100644 index 000000000..2225e7cad --- /dev/null +++ b/dom/broadcastchannel/tests/test_broadcastchannel_any.html @@ -0,0 +1,138 @@ + + + + Test for BroadcastChannel + + + + + +
+ + + + + diff --git a/dom/broadcastchannel/tests/test_broadcastchannel_basic.html b/dom/broadcastchannel/tests/test_broadcastchannel_basic.html new file mode 100644 index 000000000..45fa3c4a9 --- /dev/null +++ b/dom/broadcastchannel/tests/test_broadcastchannel_basic.html @@ -0,0 +1,68 @@ + + + + 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 000000000..84d41db4f --- /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_close2.html b/dom/broadcastchannel/tests/test_broadcastchannel_close2.html new file mode 100644 index 000000000..a8a748c46 --- /dev/null +++ b/dom/broadcastchannel/tests/test_broadcastchannel_close2.html @@ -0,0 +1,39 @@ + + + + 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 000000000..32df390be --- /dev/null +++ b/dom/broadcastchannel/tests/test_broadcastchannel_self.html @@ -0,0 +1,38 @@ + + + + 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 000000000..16f847aca --- /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.html b/dom/broadcastchannel/tests/test_broadcastchannel_worker.html new file mode 100644 index 000000000..42e93cc1e --- /dev/null +++ b/dom/broadcastchannel/tests/test_broadcastchannel_worker.html @@ -0,0 +1,62 @@ + + + + + + Test for BroadcastChannel in workers + + + + +

+ +
+
+
+ + 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 000000000..8b1b03c4e --- /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 000000000..6aa164e94 --- /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_invalidState.html b/dom/broadcastchannel/tests/test_invalidState.html new file mode 100644 index 000000000..8e4a1df35 --- /dev/null +++ b/dom/broadcastchannel/tests/test_invalidState.html @@ -0,0 +1,28 @@ + + + + Test for BroadcastChannel.postMessage invalid State + + + + + +
+ + + + + diff --git a/dom/broadcastchannel/tests/test_ordering.html b/dom/broadcastchannel/tests/test_ordering.html new file mode 100644 index 000000000..eab1f955e --- /dev/null +++ b/dom/broadcastchannel/tests/test_ordering.html @@ -0,0 +1,65 @@ + + + + Test for BroadcastChannel.postMessage invalid State + + + + + +
+ + + + + -- cgit v1.2.3