diff --git a/dom/broadcastchannel/BroadcastChannel.cpp b/dom/broadcastchannel/BroadcastChannel.cpp index 753377f015aa..a37e342e4519 100644 --- a/dom/broadcastchannel/BroadcastChannel.cpp +++ b/dom/broadcastchannel/BroadcastChannel.cpp @@ -7,6 +7,7 @@ #include "BroadcastChannelChild.h" #include "mozilla/dom/BroadcastChannelBinding.h" #include "mozilla/dom/Navigator.h" +#include "mozilla/dom/StructuredCloneUtils.h" #include "mozilla/ipc/BackgroundChild.h" #include "mozilla/ipc/BackgroundUtils.h" #include "mozilla/ipc/PBackgroundChild.h" @@ -28,6 +29,22 @@ namespace dom { using namespace workers; +class BroadcastChannelMessage MOZ_FINAL +{ +public: + NS_INLINE_DECL_REFCOUNTING(BroadcastChannelMessage) + + JSAutoStructuredCloneBuffer mBuffer; + StructuredCloneClosure mClosure; + + BroadcastChannelMessage() + { } + +private: + ~BroadcastChannelMessage() + { } +}; + namespace { void @@ -159,9 +176,9 @@ public: NS_DECL_ISUPPORTS PostMessageRunnable(BroadcastChannelChild* aActor, - const nsAString& aMessage) + BroadcastChannelMessage* aData) : mActor(aActor) - , mMessage(aMessage) + , mData(aData) { MOZ_ASSERT(mActor); } @@ -169,9 +186,24 @@ public: NS_IMETHODIMP Run() { MOZ_ASSERT(mActor); - if (!mActor->IsActorDestroyed()) { - mActor->SendPostMessage(mMessage); + if (mActor->IsActorDestroyed()) { + return NS_OK; } + + BroadcastChannelMessageData message; + + SerializedStructuredCloneBuffer& buffer = message.data(); + buffer.data = mData->mBuffer.data(); + buffer.dataLength = mData->mBuffer.nbytes(); + +#ifdef DEBUG + { + const nsTArray>& blobs = mData->mClosure.mBlobs; + MOZ_ASSERT(blobs.IsEmpty()); + } +#endif + + mActor->SendPostMessage(message); return NS_OK; } @@ -185,7 +217,7 @@ private: ~PostMessageRunnable() {} nsRefPtr mActor; - nsString mMessage; + nsRefPtr mData; }; NS_IMPL_ISUPPORTS(PostMessageRunnable, nsICancelableRunnable, nsIRunnable) @@ -460,22 +492,38 @@ BroadcastChannel::Constructor(const GlobalObject& aGlobal, } void -BroadcastChannel::PostMessage(const nsAString& aMessage, ErrorResult& aRv) +BroadcastChannel::PostMessage(JSContext* aCx, JS::Handle aMessage, + ErrorResult& aRv) { if (mState != StateActive) { aRv.Throw(NS_ERROR_FAILURE); return; } - PostMessageInternal(aMessage); + PostMessageInternal(aCx, aMessage, aRv); } void -BroadcastChannel::PostMessageInternal(const nsAString& aMessage) +BroadcastChannel::PostMessageInternal(JSContext* aCx, + JS::Handle aMessage, + ErrorResult& aRv) +{ + nsRefPtr data = new BroadcastChannelMessage(); + + if (!WriteStructuredClone(aCx, aMessage, data->mBuffer, data->mClosure)) { + aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); + return; + } + + PostMessageData(data); +} + +void +BroadcastChannel::PostMessageData(BroadcastChannelMessage* aData) { if (mActor) { nsRefPtr runnable = - new PostMessageRunnable(mActor, aMessage); + new PostMessageRunnable(mActor, aData); if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) { NS_WARNING("Failed to dispatch to the current thread!"); @@ -484,7 +532,7 @@ BroadcastChannel::PostMessageInternal(const nsAString& aMessage) return; } - mPendingMessages.AppendElement(aMessage); + mPendingMessages.AppendElement(aData); } void @@ -527,7 +575,7 @@ BroadcastChannel::ActorCreated(ipc::PBackgroundChild* aActor) // Flush pending messages. for (uint32_t i = 0; i < mPendingMessages.Length(); ++i) { - PostMessageInternal(mPendingMessages[i]); + PostMessageData(mPendingMessages[i]); } mPendingMessages.Clear(); diff --git a/dom/broadcastchannel/BroadcastChannel.h b/dom/broadcastchannel/BroadcastChannel.h index ec959a5db0f2..f268882e512d 100644 --- a/dom/broadcastchannel/BroadcastChannel.h +++ b/dom/broadcastchannel/BroadcastChannel.h @@ -24,6 +24,7 @@ class WorkerFeature; } class BroadcastChannelChild; +struct BroadcastChannelMessage; class BroadcastChannel MOZ_FINAL : public DOMEventTargetHelper @@ -55,7 +56,8 @@ public: aName = mChannel; } - void PostMessage(const nsAString& aMessage, ErrorResult& aRv); + void PostMessage(JSContext* aCx, JS::Handle aMessage, + ErrorResult& aRv); void Close(); @@ -85,12 +87,15 @@ private: ~BroadcastChannel(); - void PostMessageInternal(const nsAString& aMessage); + void PostMessageData(BroadcastChannelMessage* aData); + + void PostMessageInternal(JSContext* aCx, JS::Handle aMessage, + ErrorResult& aRv); void UpdateMustKeepAlive(); nsRefPtr mActor; - nsTArray mPendingMessages; + nsTArray> mPendingMessages; workers::WorkerFeature* mWorkerFeature; diff --git a/dom/broadcastchannel/BroadcastChannelChild.cpp b/dom/broadcastchannel/BroadcastChannelChild.cpp index b420a3c6c178..462e1fb82dfa 100644 --- a/dom/broadcastchannel/BroadcastChannelChild.cpp +++ b/dom/broadcastchannel/BroadcastChannelChild.cpp @@ -8,6 +8,9 @@ #include "jsapi.h" #include "mozilla/dom/MessageEvent.h" #include "mozilla/dom/MessageEventBinding.h" +#include "mozilla/dom/StructuredCloneUtils.h" +#include "mozilla/dom/WorkerPrivate.h" +#include "mozilla/dom/WorkerScope.h" #include "mozilla/dom/ScriptSettings.h" #include "mozilla/ipc/PBackgroundChild.h" #include "WorkerPrivate.h" @@ -34,7 +37,7 @@ BroadcastChannelChild::~BroadcastChannelChild() } bool -BroadcastChannelChild::RecvNotify(const nsString& aMessage) +BroadcastChannelChild::RecvNotify(const BroadcastChannelMessageData& aData) { nsCOMPtr helper = mBC; nsCOMPtr eventTarget = do_QueryInterface(helper); @@ -50,39 +53,36 @@ BroadcastChannelChild::RecvNotify(const nsString& aMessage) return true; } - if (NS_IsMainThread()) { - AutoJSAPI autoJS; - if (!autoJS.Init(mBC->GetParentObject())) { - NS_WARNING("Dropping message"); - return true; - } + AutoJSAPI jsapi; + nsCOMPtr globalObject; - Notify(autoJS.cx(), aMessage); + 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; } - WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); - MOZ_ASSERT(workerPrivate); + JSContext* cx = jsapi.cx(); - Notify(workerPrivate->GetJSContext(), aMessage); - return true; -} + const SerializedStructuredCloneBuffer& buffer = aData.data(); + StructuredCloneData cloneData; + cloneData.mData = buffer.data; + cloneData.mDataLength = buffer.dataLength; -void -BroadcastChannelChild::Notify(JSContext* aCx, const nsString& aMessage) -{ - JS::Rooted str(aCx, - JS_NewUCStringCopyN(aCx, aMessage.get(), - aMessage.Length())); - if (!str) { - // OOM, no exception needed. - NS_WARNING("Failed allocating a JS string. Probably OOM."); - return; + JS::Rooted value(cx, JS::NullValue()); + if (cloneData.mDataLength && !ReadStructuredClone(cx, cloneData, &value)) { + JS_ClearPendingException(cx); + return false; } - JS::Rooted value(aCx, JS::StringValue(str)); - - RootedDictionary init(aCx); + RootedDictionary init(cx); init.mBubbles = false; init.mCancelable = false; init.mOrigin.Construct(mOrigin); @@ -93,13 +93,15 @@ BroadcastChannelChild::Notify(JSContext* aCx, const nsString& aMessage) MessageEvent::Constructor(mBC, NS_LITERAL_STRING("message"), init, rv); if (rv.Failed()) { NS_WARNING("Failed to create a MessageEvent object."); - return; + return true; } event->SetTrusted(true); bool status; mBC->DispatchEvent(static_cast(event.get()), &status); + + return true; } void diff --git a/dom/broadcastchannel/BroadcastChannelChild.h b/dom/broadcastchannel/BroadcastChannelChild.h index 7a3329e763d8..26ab6886043d 100644 --- a/dom/broadcastchannel/BroadcastChannelChild.h +++ b/dom/broadcastchannel/BroadcastChannelChild.h @@ -29,7 +29,8 @@ public: mBC = aBC; } - virtual bool RecvNotify(const nsString& aMessage) MOZ_OVERRIDE; + virtual bool RecvNotify(const BroadcastChannelMessageData& aData) + MOZ_OVERRIDE; bool IsActorDestroyed() const { @@ -42,8 +43,6 @@ private: ~BroadcastChannelChild(); - void Notify(JSContext* aCx, const nsString& aMessage); - void ActorDestroy(ActorDestroyReason aWhy); // This raw pointer is actually the parent object. diff --git a/dom/broadcastchannel/BroadcastChannelParent.cpp b/dom/broadcastchannel/BroadcastChannelParent.cpp index 79794aad5bf3..83b360a7a1d9 100644 --- a/dom/broadcastchannel/BroadcastChannelParent.cpp +++ b/dom/broadcastchannel/BroadcastChannelParent.cpp @@ -31,7 +31,8 @@ BroadcastChannelParent::~BroadcastChannelParent() } bool -BroadcastChannelParent::RecvPostMessage(const nsString& aMessage) +BroadcastChannelParent::RecvPostMessage( + const BroadcastChannelMessageData& aData) { AssertIsOnBackgroundThread(); @@ -39,7 +40,7 @@ BroadcastChannelParent::RecvPostMessage(const nsString& aMessage) return false; } - mService->PostMessage(this, aMessage, mOrigin, mChannel); + mService->PostMessage(this, aData, mOrigin, mChannel); return true; } @@ -73,14 +74,15 @@ BroadcastChannelParent::ActorDestroy(ActorDestroyReason aWhy) } void -BroadcastChannelParent::CheckAndDeliver(const nsString& aMessage, - const nsString& aOrigin, - const nsString& aChannel) +BroadcastChannelParent::CheckAndDeliver( + const BroadcastChannelMessageData& aData, + const nsString& aOrigin, + const nsString& aChannel) { AssertIsOnBackgroundThread(); if (aOrigin == mOrigin && aChannel == mChannel) { - unused << SendNotify(aMessage); + unused << SendNotify(aData); } } diff --git a/dom/broadcastchannel/BroadcastChannelParent.h b/dom/broadcastchannel/BroadcastChannelParent.h index de6be5adead0..752d34612e2c 100644 --- a/dom/broadcastchannel/BroadcastChannelParent.h +++ b/dom/broadcastchannel/BroadcastChannelParent.h @@ -22,7 +22,7 @@ class BroadcastChannelParent MOZ_FINAL : public PBroadcastChannelParent friend class mozilla::ipc::BackgroundParentImpl; public: - void CheckAndDeliver(const nsString& aMessage, + void CheckAndDeliver(const BroadcastChannelMessageData& aData, const nsString& aOrigin, const nsString& aChannel); @@ -31,7 +31,8 @@ private: const nsAString& aChannel); ~BroadcastChannelParent(); - virtual bool RecvPostMessage(const nsString& aMessage) MOZ_OVERRIDE; + virtual bool + RecvPostMessage(const BroadcastChannelMessageData& aData) MOZ_OVERRIDE; virtual bool RecvClose() MOZ_OVERRIDE; diff --git a/dom/broadcastchannel/BroadcastChannelService.cpp b/dom/broadcastchannel/BroadcastChannelService.cpp index e1045e333dc0..e215d36aa0d5 100644 --- a/dom/broadcastchannel/BroadcastChannelService.cpp +++ b/dom/broadcastchannel/BroadcastChannelService.cpp @@ -75,11 +75,11 @@ namespace { struct MOZ_STACK_CLASS PostMessageData MOZ_FINAL { PostMessageData(BroadcastChannelParent* aParent, - const nsAString& aMessage, + const BroadcastChannelMessageData& aData, const nsAString& aOrigin, const nsAString& aChannel) : mParent(aParent) - , mMessage(aMessage) + , mData(aData) , mOrigin(aOrigin) , mChannel(aChannel) { @@ -93,7 +93,7 @@ struct MOZ_STACK_CLASS PostMessageData MOZ_FINAL } BroadcastChannelParent* mParent; - const nsString mMessage; + const BroadcastChannelMessageData& mData; const nsString mOrigin; const nsString mChannel; }; @@ -108,7 +108,7 @@ PostMessageEnumerator(nsPtrHashKey* aKey, void* aPtr) MOZ_ASSERT(parent); if (parent != data->mParent) { - parent->CheckAndDeliver(data->mMessage, data->mOrigin, data->mChannel); + parent->CheckAndDeliver(data->mData, data->mOrigin, data->mChannel); } return PL_DHASH_NEXT; @@ -118,7 +118,7 @@ PostMessageEnumerator(nsPtrHashKey* aKey, void* aPtr) void BroadcastChannelService::PostMessage(BroadcastChannelParent* aParent, - const nsAString& aMessage, + const BroadcastChannelMessageData& aData, const nsAString& aOrigin, const nsAString& aChannel) { @@ -126,7 +126,7 @@ BroadcastChannelService::PostMessage(BroadcastChannelParent* aParent, MOZ_ASSERT(aParent); MOZ_ASSERT(mAgents.Contains(aParent)); - PostMessageData data(aParent, aMessage, aOrigin, aChannel); + PostMessageData data(aParent, aData, aOrigin, aChannel); mAgents.EnumerateEntries(PostMessageEnumerator, &data); } diff --git a/dom/broadcastchannel/BroadcastChannelService.h b/dom/broadcastchannel/BroadcastChannelService.h index 338cd51f57e1..83341d81aa92 100644 --- a/dom/broadcastchannel/BroadcastChannelService.h +++ b/dom/broadcastchannel/BroadcastChannelService.h @@ -13,6 +13,7 @@ namespace mozilla { namespace dom { class BroadcastChannelParent; +class BroadcastChannelMessageData; class BroadcastChannelService MOZ_FINAL { @@ -25,7 +26,7 @@ public: void UnregisterActor(BroadcastChannelParent* aParent); void PostMessage(BroadcastChannelParent* aParent, - const nsAString& aMessage, + const BroadcastChannelMessageData& aData, const nsAString& aOrigin, const nsAString& aChannel); diff --git a/dom/broadcastchannel/PBroadcastChannel.ipdl b/dom/broadcastchannel/PBroadcastChannel.ipdl index 62a5307fac06..8115283f94ef 100644 --- a/dom/broadcastchannel/PBroadcastChannel.ipdl +++ b/dom/broadcastchannel/PBroadcastChannel.ipdl @@ -4,20 +4,27 @@ include protocol PBackground; +using struct mozilla::SerializedStructuredCloneBuffer from "ipc/IPCMessageUtils.h"; + namespace mozilla { namespace dom { +struct BroadcastChannelMessageData +{ + SerializedStructuredCloneBuffer data; +}; + // This protocol is used for the BroadcastChannel API protocol PBroadcastChannel { manager PBackground; parent: - PostMessage(nsString message); + PostMessage(BroadcastChannelMessageData message); Close(); child: - Notify(nsString message); + Notify(BroadcastChannelMessageData message); __delete__(); }; diff --git a/dom/broadcastchannel/tests/broadcastchannel_worker.js b/dom/broadcastchannel/tests/broadcastchannel_worker.js index 30d27e83ac19..4714d59d0216 100644 --- a/dom/broadcastchannel/tests/broadcastchannel_worker.js +++ b/dom/broadcastchannel/tests/broadcastchannel_worker.js @@ -10,8 +10,7 @@ onmessage = function(evt) { var bc = new BroadcastChannel('foobar'); bc.addEventListener('message', function(event) { - postMessage(event.data == "hello world from the window" ? "OK" : "KO"); - bc.postMessage("hello world from the worker"); + bc.postMessage(event.data == "hello world from the window" ? "hello world from the worker" : "KO"); bc.close(); }, false); diff --git a/dom/broadcastchannel/tests/broadcastchannel_worker_any.js b/dom/broadcastchannel/tests/broadcastchannel_worker_any.js new file mode 100644 index 000000000000..da8625c4d8e9 --- /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/mochitest.ini b/dom/broadcastchannel/tests/mochitest.ini index 63ad9725adc2..ab8869a45367 100644 --- a/dom/broadcastchannel/tests/mochitest.ini +++ b/dom/broadcastchannel/tests/mochitest.ini @@ -5,7 +5,9 @@ support-files = broadcastchannel_sharedWorker.js broadcastchannel_worker.js broadcastchannel_worker_alive.js + broadcastchannel_worker_any.js +[test_broadcastchannel_any.html] [test_broadcastchannel_basic.html] [test_broadcastchannel_close.html] [test_broadcastchannel_self.html] diff --git a/dom/broadcastchannel/tests/test_broadcastchannel_any.html b/dom/broadcastchannel/tests/test_broadcastchannel_any.html new file mode 100644 index 000000000000..748f321ac371 --- /dev/null +++ b/dom/broadcastchannel/tests/test_broadcastchannel_any.html @@ -0,0 +1,109 @@ + + + + Test for BroadcastChannel + + + + + +
+ + + + + diff --git a/dom/broadcastchannel/tests/test_broadcastchannel_worker.html b/dom/broadcastchannel/tests/test_broadcastchannel_worker.html index 748d2c840e3b..6f731eb7a0fb 100644 --- a/dom/broadcastchannel/tests/test_broadcastchannel_worker.html +++ b/dom/broadcastchannel/tests/test_broadcastchannel_worker.html @@ -29,8 +29,6 @@ function testWorker(x) { if (event.data == "READY") { ok(true, "Worker is ready!"); bc.postMessage('hello world from the window'); - } else if(event.data == "OK") { - ok(true, "Worker has received the message"); } else { ok(false, "Something wrong happened"); } diff --git a/dom/broadcastchannel/tests/test_broadcastchannel_worker_alive.html b/dom/broadcastchannel/tests/test_broadcastchannel_worker_alive.html index 7fa358819cd2..340431b3cef0 100644 --- a/dom/broadcastchannel/tests/test_broadcastchannel_worker_alive.html +++ b/dom/broadcastchannel/tests/test_broadcastchannel_worker_alive.html @@ -28,7 +28,7 @@ function runTests() { if (event.data == "READY") { ok(true, "Worker is ready!"); } else { - is(id, event.data, "The message is correct"); + is(id, event.data, "The message is correct: " + id); } for (var i = 0; i < 3; ++i) { @@ -38,6 +38,7 @@ function runTests() { if (id == 5) { SimpleTest.finish(); + return; } event.target.postMessage(++id); diff --git a/dom/webidl/BroadcastChannel.webidl b/dom/webidl/BroadcastChannel.webidl index 1d0934ea835d..37c531d4a700 100644 --- a/dom/webidl/BroadcastChannel.webidl +++ b/dom/webidl/BroadcastChannel.webidl @@ -14,7 +14,7 @@ interface BroadcastChannel : EventTarget { readonly attribute DOMString name; [Throws] - void postMessage(DOMString message); + void postMessage(any message); void close();