diff --git a/dom/base/MessagePort.cpp b/dom/base/MessagePort.cpp index e2aa15457ae1..a7b593cad814 100644 --- a/dom/base/MessagePort.cpp +++ b/dom/base/MessagePort.cpp @@ -82,5 +82,25 @@ MessagePort::Entangle(MessagePort* aMessagePort) mEntangledPort = aMessagePort; } +already_AddRefed +MessagePort::Clone(nsPIDOMWindow* aWindow) +{ + nsRefPtr newPort = new MessagePort(aWindow); + + // TODO Move all the events in the port message queue of original port to the + // port message queue of new port, if any, leaving the new port's port + // message queue in its initial disabled state. + + if (mEntangledPort) { + nsRefPtr port = mEntangledPort; + mEntangledPort = nullptr; + + newPort->Entangle(port); + port->Entangle(newPort); + } + + return newPort.forget(); +} + } // namespace dom } // namespace mozilla diff --git a/dom/base/MessagePort.h b/dom/base/MessagePort.h index 5dab2db04589..84987c748f6a 100644 --- a/dom/base/MessagePort.h +++ b/dom/base/MessagePort.h @@ -49,6 +49,12 @@ public: void Entangle(MessagePort* aMessagePort); + // Duplicate this message port. This method is used by the Structured Clone + // Algorithm and makes the new MessagePort active with the entangled + // MessagePort of this object. + already_AddRefed + Clone(nsPIDOMWindow* aWindow); + private: nsRefPtr mEntangledPort; }; diff --git a/dom/base/StructuredCloneTags.h b/dom/base/StructuredCloneTags.h index aa3781b2a3e6..533d39f1b5e1 100644 --- a/dom/base/StructuredCloneTags.h +++ b/dom/base/StructuredCloneTags.h @@ -28,6 +28,7 @@ enum StructuredCloneTags { // These tags are used for both main thread and workers. SCTAG_DOM_IMAGEDATA, + SCTAG_DOM_MESSAGEPORT, SCTAG_DOM_MAX }; diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 752389dfcb18..31480eba8f72 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -189,6 +189,8 @@ #include "prenv.h" #include "prprf.h" +#include "mozilla/dom/MessagePort.h" +#include "mozilla/dom/MessagePortBinding.h" #include "mozilla/dom/indexedDB/IDBFactory.h" #include "mozilla/dom/quota/QuotaManager.h" @@ -6750,6 +6752,7 @@ namespace { struct StructuredCloneInfo { PostMessageEvent* event; bool subsumes; + nsPIDOMWindow* window; }; static JSObject* @@ -6779,6 +6782,21 @@ PostMessageReadStructuredClone(JSContext* cx, } } + if (tag == SCTAG_DOM_MESSAGEPORT) { + NS_ASSERTION(!data, "Data should be empty"); + + MessagePort* port; + if (JS_ReadBytes(reader, &port, sizeof(port))) { + JS::Rooted global(cx, JS::CurrentGlobalOrNull(cx)); + if (global) { + JS::Rooted obj(cx, port->WrapObject(cx, global)); + if (JS_WrapObject(cx, obj.address())) { + return obj; + } + } + } + } + const JSStructuredCloneCallbacks* runtimeCallbacks = js::GetContextStructuredCloneCallbacks(cx); @@ -6819,6 +6837,16 @@ PostMessageWriteStructuredClone(JSContext* cx, scInfo->event->StoreISupports(supports); } + MessagePort* port = nullptr; + nsresult rv = UNWRAP_OBJECT(MessagePort, cx, obj, port); + if (NS_SUCCEEDED(rv) && scInfo->subsumes) { + nsRefPtr newPort = port->Clone(scInfo->window); + + return JS_WriteUint32Pair(writer, SCTAG_DOM_MESSAGEPORT, 0) && + JS_WriteBytes(writer, &newPort, sizeof(newPort)) && + scInfo->event->StoreISupports(newPort); + } + const JSStructuredCloneCallbacks* runtimeCallbacks = js::GetContextStructuredCloneCallbacks(cx); @@ -6910,6 +6938,7 @@ PostMessageEvent::Run() { StructuredCloneInfo scInfo; scInfo.event = this; + scInfo.window = targetWindow; if (!buffer.read(cx, messageData.address(), &kPostMessageCallbacks, &scInfo)) { @@ -7056,6 +7085,7 @@ nsGlobalWindow::PostMessageMoz(const JS::Value& aMessage, JSAutoStructuredCloneBuffer buffer; StructuredCloneInfo scInfo; scInfo.event = event; + scInfo.window = this; nsIPrincipal* principal = GetPrincipal(); if (NS_FAILED(callerPrin->Subsumes(principal, &scInfo.subsumes))) diff --git a/dom/base/test/Makefile.in b/dom/base/test/Makefile.in index f6974304298c..1a8f9a00904b 100644 --- a/dom/base/test/Makefile.in +++ b/dom/base/test/Makefile.in @@ -32,6 +32,8 @@ MOCHITEST_FILES = \ test_setting_opener.html \ test_error.html \ test_messageChannel.html \ + test_messageChannel_cloning.html \ + iframe_messageChannel_cloning.html \ $(NULL) MOCHITEST_CHROME_FILES = \ diff --git a/dom/base/test/iframe_messageChannel_cloning.html b/dom/base/test/iframe_messageChannel_cloning.html new file mode 100644 index 000000000000..ee53e855a730 --- /dev/null +++ b/dom/base/test/iframe_messageChannel_cloning.html @@ -0,0 +1,22 @@ + + + + + + + diff --git a/dom/base/test/test_messageChannel_cloning.html b/dom/base/test/test_messageChannel_cloning.html new file mode 100644 index 000000000000..30327d5f1624 --- /dev/null +++ b/dom/base/test/test_messageChannel_cloning.html @@ -0,0 +1,70 @@ + + + + + + Test for Bug 677638 - port cloning + + + + +Mozilla Bug 677638 +
+
+
+ + +