ported mozilla patches:

- Bug 848294 - Update MessageEvent to be compatible with the spec, r=bz
- Bug 913761 - Something is wrong when transferring MessagePort object via MessageChannel. r=smaug
- Bug 917254 - Only enable MessageEvent.ports when MessagePort is enabled; r=smaug
This commit is contained in:
2018-08-26 00:35:59 +08:00
parent 366f2c3245
commit 43b0deedf0
18 changed files with 376 additions and 62 deletions
+91 -4
View File
@@ -4,6 +4,11 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsDOMMessageEvent.h"
#include "mozilla/dom/MessagePort.h"
#include "mozilla/dom/MessagePortBinding.h"
#include "mozilla/dom/MessagePortList.h"
#include "mozilla/dom/UnionTypes.h"
#include "nsContentUtils.h"
#include "jsapi.h"
@@ -12,11 +17,15 @@ using namespace mozilla::dom;
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMMessageEvent, nsDOMEvent)
tmp->mData = JSVAL_VOID;
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSource)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindowSource)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPortSource)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPorts)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMMessageEvent, nsDOMEvent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSource)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindowSource)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPortSource)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPorts)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(nsDOMMessageEvent, nsDOMEvent)
@@ -79,10 +88,88 @@ nsDOMMessageEvent::GetLastEventId(nsAString& aLastEventId)
NS_IMETHODIMP
nsDOMMessageEvent::GetSource(nsIDOMWindow** aSource)
{
NS_IF_ADDREF(*aSource = mSource);
NS_IF_ADDREF(*aSource = mWindowSource);
return NS_OK;
}
void
nsDOMMessageEvent::GetSource(Nullable<mozilla::dom::WindowProxyOrMessagePortReturnValue>& aValue) const
{
if (mWindowSource) {
aValue.SetValue().SetAsWindowProxy() = mWindowSource;
} else if (mPortSource) {
aValue.SetValue().SetAsMessagePort() = mPortSource;
}
}
/* static */ already_AddRefed<nsDOMMessageEvent>
nsDOMMessageEvent::Constructor(const mozilla::dom::GlobalObject& aGlobal,
JSContext* aCx, const nsAString& aType,
const mozilla::dom::MessageEventInit& aParam,
mozilla::ErrorResult& aRv)
{
nsCOMPtr<mozilla::dom::EventTarget> t =
do_QueryInterface(aGlobal.Get());
nsRefPtr<nsDOMMessageEvent> event =
new nsDOMMessageEvent(t, nullptr, nullptr);
aRv = event->InitEvent(aType, aParam.mBubbles, aParam.mCancelable);
if (aRv.Failed()) {
return nullptr;
}
bool trusted = event->Init(t);
event->SetTrusted(trusted);
if (aParam.mData.WasPassed()) {
event->mData = aParam.mData.Value();
}
NS_HOLD_JS_OBJECTS(event.get(), nsDOMMessageEvent);
if (aParam.mOrigin.WasPassed()) {
event->mOrigin = aParam.mOrigin.Value();
}
if (aParam.mLastEventId.WasPassed()) {
event->mLastEventId = aParam.mLastEventId.Value();
}
if (aParam.mSource) {
nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative;
nsContentUtils::XPConnect()->
GetWrappedNativeOfJSObject(aCx, aParam.mSource,
getter_AddRefs(wrappedNative));
if (wrappedNative) {
event->mWindowSource = do_QueryWrappedNative(wrappedNative);
}
if (!event->mWindowSource) {
MessagePort* port = nullptr;
nsresult rv = mozilla::dom::UnwrapObject<MessagePort>(aCx, aParam.mSource, port);
if (NS_FAILED(rv)) {
aRv.Throw(NS_ERROR_INVALID_ARG);
return nullptr;
}
event->mPortSource = port;
}
}
if (aParam.mPorts.WasPassed() && !aParam.mPorts.Value().IsNull()) {
nsTArray<nsRefPtr<MessagePort> > ports;
for (uint32_t i = 0, len = aParam.mPorts.Value().Value().Length(); i < len; ++i) {
ports.AppendElement(aParam.mPorts.Value().Value()[i].get());
}
event->mPorts = new MessagePortList(static_cast<nsDOMEventBase*>(event),
ports);
}
return event.forget();
}
NS_IMETHODIMP
nsDOMMessageEvent::InitMessageEvent(const nsAString& aType,
bool aCanBubble,
@@ -99,7 +186,7 @@ nsDOMMessageEvent::InitMessageEvent(const nsAString& aType,
NS_HOLD_JS_OBJECTS(this, nsDOMMessageEvent);
mOrigin = aOrigin;
mLastEventId = aLastEventId;
mSource = aSource;
mWindowSource = aSource;
return NS_OK;
}
+19 -17
View File
@@ -12,6 +12,13 @@
#include "jsapi.h"
#include "mozilla/dom/MessageEventBinding.h"
namespace mozilla {
namespace dom {
class MessagePortList;
class WindowProxyOrMessagePortReturnValue;
}
}
/**
* Implements the MessageEvent event, used for cross-document messaging and
* server-sent events.
@@ -44,31 +51,26 @@ public:
JS::Value GetData(JSContext* aCx, mozilla::ErrorResult& aRv);
already_AddRefed<nsIDOMWindow> GetSource()
void GetSource(Nullable<mozilla::dom::WindowProxyOrMessagePortReturnValue>& aValue) const;
mozilla::dom::MessagePortList* GetPorts()
{
nsCOMPtr<nsIDOMWindow> ret = mSource;
return ret.forget();
return mPorts;
}
void InitMessageEvent(JSContext* aCx,
const nsAString& aType,
bool aCanBubble,
bool aCancelable,
JS::Handle<JS::Value> aData,
const nsAString& aOrigin,
const nsAString& aLastEventId,
nsIDOMWindow* aSource,
mozilla::ErrorResult& aRv)
{
aRv = InitMessageEvent(aType, aCanBubble, aCancelable, aData,
aOrigin, aLastEventId, aSource);
}
static already_AddRefed<nsDOMMessageEvent>
Constructor(const mozilla::dom::GlobalObject& aGlobal, JSContext* aCx,
const nsAString& aType,
const mozilla::dom::MessageEventInit& aEventInit,
mozilla::ErrorResult& aRv);
private:
JS::Heap<JS::Value> mData;
nsString mOrigin;
nsString mLastEventId;
nsCOMPtr<nsIDOMWindow> mSource;
nsCOMPtr<nsIDOMWindow> mWindowSource;
nsCOMPtr<mozilla::dom::MessagePort> mPortSource;
nsRefPtr<mozilla::dom::MessagePortList> mPorts;
};
#endif // nsDOMMessageEvent_h__
+1
View File
@@ -102,6 +102,7 @@ MOCHITEST_FILES = \
test_focus_disabled.html \
test_bug847597.html \
test_bug855741.html \
test_messageEvent.html \
$(NULL)
# Disabled on Windows due to intermittent failures.
@@ -0,0 +1,66 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=848294
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 848294</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/WindowSnapshot.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="application/javascript">
function runTest() {
var channel = new MessageChannel();
var tests = [
{},
{ data: 42 },
{ data: {} },
{ data: true, origin: 'wow' },
{ data: [], lastEventId: 'wow2' },
{ data: null, source: null },
{ data: window, source: window },
{ data: window, source: channel.port1 },
{ data: window, source: channel.port1, ports: [ channel.port1, channel.port2 ] },
{ data: null, ports: null },
];
while (tests.length) {
var test = tests.shift();
var e = new MessageEvent('message', test);
ok(e, "MessageEvent created");
is(e.type, 'message', 'MessageEvent.type is right');
is(e.data, 'data' in test ? test.data : undefined, 'MessageEvent.data is ok');
is(e.origin, 'origin' in test ? test.origin : '', 'MessageEvent.origin is ok');
is(e.lastEventId, 'lastEventId' in test ? test.lastEventId : '', 'MessageEvent.lastEventId is ok');
is(e.source, 'source' in test ? test.source : undefined, 'MessageEvent.source is ok');
if (test.ports != undefined) {
is(e.ports.length, test.ports.length, 'MessageEvent.ports is ok');
is(e.ports, e.ports, 'MessageEvent.ports is ok');
} else {
ok(!('ports' in test) || test.ports == null, 'MessageEvent.ports is ok');
}
}
try {
var e = new MessageEvent('foobar', { source: 42 });
ok(false, "Source has to be a window or a port");
} catch(e) {
ok(true, "Source has to be a window or a port");
}
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [["dom.messageChannel.enabled", true]]}, runTest);
</script>
</body>
</html>
+6 -4
View File
@@ -110,7 +110,8 @@ PostMessageReadStructuredClone(JSContext* cx,
uint32_t data,
void* closure)
{
NS_ASSERTION(closure, "Must have closure!");
StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure);
NS_ASSERTION(scInfo, "Must have scInfo!");
if (tag == SCTAG_DOM_BLOB || tag == SCTAG_DOM_FILELIST) {
NS_ASSERTION(!data, "Data should be empty");
@@ -139,6 +140,7 @@ PostMessageReadStructuredClone(JSContext* cx,
if (global) {
JS::Rooted<JSObject*> obj(cx, port->WrapObject(cx, global));
if (JS_WrapObject(cx, obj.address())) {
port->BindToOwner(scInfo->mPort->GetOwner());
return obj;
}
}
@@ -191,7 +193,7 @@ PostMessageWriteStructuredClone(JSContext* cx,
MessagePort* port = nullptr;
nsresult rv = mozilla::dom::UnwrapObject<MessagePort>(cx, obj, port);
if (NS_SUCCEEDED(rv)) {
nsRefPtr<MessagePort> newPort = port->Clone(scInfo->mPort->GetOwner());
nsRefPtr<MessagePort> newPort = port->Clone();
return JS_WriteUint32Pair(writer, SCTAG_DOM_MESSAGEPORT, 0) &&
JS_WriteBytes(writer, &newPort, sizeof(newPort)) &&
@@ -455,9 +457,9 @@ MessagePort::Entangle(MessagePort* aMessagePort)
}
already_AddRefed<MessagePort>
MessagePort::Clone(nsPIDOMWindow* aWindow)
MessagePort::Clone()
{
nsRefPtr<MessagePort> newPort = new MessagePort(aWindow->GetCurrentInnerWindow());
nsRefPtr<MessagePort> newPort = new MessagePort(nullptr);
// Move all the events in the port message queue of original port.
newPort->mMessageQueue.SwapElements(mMessageQueue);
+1 -1
View File
@@ -66,7 +66,7 @@ public:
// Algorithm and makes the new MessagePort active with the entangled
// MessagePort of this object.
already_AddRefed<MessagePort>
Clone(nsPIDOMWindow* aWindow);
Clone();
private:
// Dispatch events from the Message Queue using a nsRunnable.
+29
View File
@@ -0,0 +1,29 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 "MessagePortList.h"
#include "mozilla/dom/MessagePortListBinding.h"
#include "mozilla/dom/MessagePort.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(MessagePortList, mOwner, mPorts)
NS_IMPL_CYCLE_COLLECTING_ADDREF(MessagePortList)
NS_IMPL_CYCLE_COLLECTING_RELEASE(MessagePortList)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MessagePortList)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
JSObject*
MessagePortList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
{
return MessagePortListBinding::Wrap(aCx, aScope, this);
}
} // namespace dom
} // namespace mozilla
+76
View File
@@ -0,0 +1,76 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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_MessagePortList_h
#define mozilla_dom_MessagePortList_h
#include "mozilla/Attributes.h"
#include "mozilla/ErrorResult.h"
#include "nsCycleCollectionParticipant.h"
#include "mozilla/dom/MessagePort.h"
#include "nsWrapperCache.h"
#include "nsAutoPtr.h"
#include "nsTArray.h"
namespace mozilla {
namespace dom {
class MessagePortList MOZ_FINAL : public nsISupports
, public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MessagePortList)
public:
MessagePortList(nsISupports* aOwner, nsTArray<nsRefPtr<MessagePort> >& aPorts)
: mOwner(aOwner)
, mPorts(aPorts)
{
SetIsDOMBinding();
}
nsISupports*
GetParentObject() const
{
return mOwner;
}
virtual JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
uint32_t
Length() const
{
return mPorts.Length();
}
MessagePort*
Item(uint32_t aIndex)
{
return mPorts.SafeElementAt(aIndex);
}
MessagePort*
IndexedGetter(uint32_t aIndex, bool &aFound)
{
aFound = aIndex < mPorts.Length();
if (!aFound) {
return nullptr;
}
return mPorts[aIndex];
}
public:
nsCOMPtr<nsISupports> mOwner;
nsTArray<nsRefPtr<MessagePort> > mPorts;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_MessagePortList_h
+2
View File
@@ -62,6 +62,7 @@ EXPORTS.mozilla.dom += [
'DOMRequest.h',
'MessageChannel.h',
'MessagePort.h',
'MessagePortList.h',
'ScreenOrientation.h',
'StructuredCloneTags.h',
'URL.h',
@@ -76,6 +77,7 @@ CPP_SOURCES += [
'Navigator.cpp',
'MessageChannel.cpp',
'MessagePort.cpp',
'MessagePortList.cpp',
'URL.cpp',
'nsContentPermissionHelper.cpp',
'nsDOMClassInfo.cpp',
+4 -2
View File
@@ -6680,7 +6680,8 @@ PostMessageReadStructuredClone(JSContext* cx,
uint32_t data,
void* closure)
{
NS_ASSERTION(closure, "Must have closure!");
StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure);
NS_ASSERTION(scInfo, "Must have scInfo!");
if (tag == SCTAG_DOM_BLOB || tag == SCTAG_DOM_FILELIST) {
NS_ASSERTION(!data, "Data should be empty");
@@ -6709,6 +6710,7 @@ PostMessageReadStructuredClone(JSContext* cx,
if (global) {
JS::Rooted<JSObject*> obj(cx, port->WrapObject(cx, global));
if (JS_WrapObject(cx, obj.address())) {
port->BindToOwner(scInfo->window);
return obj;
}
}
@@ -6759,7 +6761,7 @@ PostMessageWriteStructuredClone(JSContext* cx,
MessagePort* port = nullptr;
nsresult rv = mozilla::dom::UnwrapObject<MessagePort>(cx, obj, port);
if (NS_SUCCEEDED(rv) && scInfo->subsumes) {
nsRefPtr<MessagePort> newPort = port->Clone(scInfo->window);
nsRefPtr<MessagePort> newPort = port->Clone();
return JS_WriteUint32Pair(writer, SCTAG_DOM_MESSAGEPORT, 0) &&
JS_WriteBytes(writer, &newPort, sizeof(newPort)) &&
+1
View File
@@ -43,6 +43,7 @@ MOCHITEST_FILES = \
test_messageChannel_unshipped.html \
test_messageChannel_pref.html \
test_url.html \
test_bug913761.html \
$(NULL)
MOCHITEST_CHROME_FILES = \
+43
View File
@@ -0,0 +1,43 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=913761
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 913761 - basic support</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=913761">Mozilla Bug 913761</a>
<script type="application/javascript">
function runTest() {
var transportChannel = new MessageChannel();
transportChannel.port1.onmessage = function (event) {
ok(true, 'Port Returned.');
var portToService = event.data.port;
portToService.onmessage = function (event) {
ok(true, "message received");
SimpleTest.finish();
};
portToService.postMessage('READY?');
}
var serviceChannel = new MessageChannel();
serviceChannel.port1.onmessage = function (event) {
if (event.data == 'READY?') {
this.postMessage('READY!');
}
}
transportChannel.port2.postMessage({ port: serviceChannel.port2} /* TODO: [serviceChannel.port2] */);
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [["dom.messageChannel.enabled", true]]}, runTest);
</script>
</body>
</html>
@@ -37,24 +37,11 @@ function sendMsg()
{
try
{
var evt = document.createEvent("MessageEvent");
var evt = new MessageEvent('message', {
bubbles: bubbles, cancelable: cancelable, data: data,
origin: origin, lastEventId: lastEventId, source: window});
ok(evt instanceof MessageEvent, "I ordered a MessageEvent!");
if (isMozilla)
{
is(evt.source, null,
"not initialized yet, so null in our implementation");
is(evt.lastEventId, "",
"not initialized yet, so empty string in our implementation");
}
evt.initMessageEvent("message", bubbles, cancelable, data, origin,
lastEventId, null);
ok(evt.source === null, "null source is fine for a MessageEvent");
evt.initMessageEvent("message", bubbles, cancelable, data, origin,
lastEventId, window);
is(evt.data, data, "unexpected data");
is(evt.origin, origin, "unexpected origin");
is(evt.lastEventId, lastEventId, "unexpected lastEventId");
@@ -25,10 +25,9 @@ function run()
{
try
{
var msg = document.createEvent("MessageEvent");
msg.initMessageEvent("message", true, true,
"foo", "http://evil.com", "",
window);
var msg = new MessageEvent('message', { bubbles: true, cancelable: true,
data: "foo", origin: "http://evil.com",
source: window });
try
{
+17 -12
View File
@@ -9,8 +9,8 @@
interface WindowProxy;
interface MessageEvent : Event
{
[Constructor(DOMString type, optional MessageEventInit eventInitDict)]
interface MessageEvent : Event {
/**
* Custom data associated with this event.
*/
@@ -32,21 +32,26 @@ interface MessageEvent : Event
readonly attribute DOMString lastEventId;
/**
* The window which originated this event.
* The window or the port which originated this event.
*/
readonly attribute WindowProxy? source;
readonly attribute (WindowProxy or MessagePort)? source;
/**
* Initializes this event with the given data, in a manner analogous to
* the similarly-named method on the nsIDOMEvent interface, also setting the
* data, origin, source, and lastEventId attributes of this appropriately.
*/
[Throws]
void initMessageEvent(DOMString aType,
boolean aCanBubble,
boolean aCancelable,
any aData,
DOMString aOrigin,
DOMString aLastEventId,
WindowProxy? aSource);
[Pref="dom.messageChannel.enabled"]
readonly attribute MessagePortList? ports;
};
dictionary MessageEventInit : EventInit {
any data;
DOMString origin;
DOMString lastEventId;
// TODO bug 767926 - This should be: (WindowProxy or MessagePort)? source;
object? source = null;
sequence<MessagePort>? ports;
};
+11
View File
@@ -0,0 +1,11 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/.
*/
[NoInterfaceObject, ArrayClass]
interface MessagePortList {
readonly attribute unsigned long length;
getter MessagePort? item(unsigned long index);
};
+1
View File
@@ -179,6 +179,7 @@ webidl_files = \
MessageChannel.webidl \
MessageEvent.webidl \
MessagePort.webidl \
MessagePortList.webidl \
MobileMessageManager.webidl \
MouseEvent.webidl \
MouseScrollEvent.webidl \
@@ -30,8 +30,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=673468
};
let wrappers_as_keys_test = function () {
let e = document.createEvent("MessageEvent");
e.initMessageEvent("foo", false, false, { dummy: document.createElement("foo") }, null, null, null);
let e = new MessageEvent("foo", { bubbles: false, cancellable: false,
data: { dummy: document.createElement("foo") }});
window.eeeevent = e;
let live_dom = e.data.dummy;