Bug 677638 - MessagePorts in Structured Clone Algorithm, r=smaug

This commit is contained in:
Andrea Marchesini 2013-09-03 14:38:51 +02:00
parent 4956384f89
commit ab6d563731
7 changed files with 151 additions and 0 deletions

View File

@ -82,5 +82,25 @@ MessagePort::Entangle(MessagePort* aMessagePort)
mEntangledPort = aMessagePort;
}
already_AddRefed<MessagePort>
MessagePort::Clone(nsPIDOMWindow* aWindow)
{
nsRefPtr<MessagePort> 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<MessagePort> port = mEntangledPort;
mEntangledPort = nullptr;
newPort->Entangle(port);
port->Entangle(newPort);
}
return newPort.forget();
}
} // namespace dom
} // namespace mozilla

View File

@ -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<MessagePort>
Clone(nsPIDOMWindow* aWindow);
private:
nsRefPtr<MessagePort> mEntangledPort;
};

View File

@ -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
};

View File

@ -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<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
if (global) {
JS::Rooted<JSObject*> 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<MessagePort> 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)))

View File

@ -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 = \

View File

@ -0,0 +1,22 @@
<!DOCTYPE HTML>
<html>
<body>
<script type="application/javascript">
function ok(a, msg) {
window.parent.postMessage({ status: a ? "OK" : "KO", message: msg }, "*");
}
window.addEventListener('message', receiveMessage, false);
function receiveMessage(evt) {
ok (evt.data, "Data received");
ok (evt.data.port instanceof MessagePort, "Data contains a MessagePort");
var a = new MessageChannel();
window.parent.postMessage({ status: "FINISH", port: a.port2 }, '*');
}
</script>
</body>
</html>

View File

@ -0,0 +1,70 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=677638
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 677638 - port cloning</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=677638">Mozilla Bug 677638</a>
<div id="content"></div>
<pre id="test">
</pre>
<script type="application/javascript">
// This test checks if MessagePorts can be shared with iframes
function test_iframe() {
window.addEventListener('message', receiveMessage, false);
function receiveMessage(evt) {
if (evt.data.status == 'OK') {
ok(true, evt.data.message);
} else if (evt.data.status == 'KO') {
ok(false, evt.data.message);
} else if (evt.data.status == 'FINISH') {
ok (evt.data.port instanceof MessagePort, "Data contains a MessagePort");
window.removeEventListener('message', receiveMessage);
runTest();
} else {
ok(false, "Unknown message");
}
}
var a = new MessageChannel();
ok(a, "MessageChannel created");
var div = document.getElementById("content");
ok(div, "Parent exists");
var ifr = document.createElement("iframe");
ifr.addEventListener("load", iframeLoaded, false);
ifr.setAttribute('src', "iframe_messageChannel_cloning.html");
div.appendChild(ifr);
function iframeLoaded() {
ifr.contentWindow.postMessage({ port: a.port2 }, '*');
}
}
var tests = [
test_iframe
];
function runTest() {
if (!tests.length) {
SimpleTest.finish();
return;
}
var test = tests.shift();
test();
}
SimpleTest.waitForExplicitFinish();
runTest();
</script>
</body>
</html>