зеркало из https://github.com/mozilla/gecko-dev.git
Bug 911972 - MessagePort and MessageChannel in workers, r=smaug, r=bent
--HG-- rename : dom/base/MessageChannel.cpp => dom/messagechannel/MessageChannel.cpp rename : dom/base/MessageChannel.h => dom/messagechannel/MessageChannel.h rename : dom/base/MessagePort.cpp => dom/messagechannel/MessagePort.cpp rename : dom/base/MessagePort.h => dom/messagechannel/MessagePort.h rename : dom/base/MessagePortList.cpp => dom/messagechannel/MessagePortList.cpp rename : dom/base/MessagePortList.h => dom/messagechannel/MessagePortList.h rename : dom/base/test/iframe_messageChannel_chrome.html => dom/messagechannel/tests/iframe_messageChannel_chrome.html rename : dom/base/test/iframe_messageChannel_cloning.html => dom/messagechannel/tests/iframe_messageChannel_cloning.html rename : dom/base/test/iframe_messageChannel_pingpong.html => dom/messagechannel/tests/iframe_messageChannel_pingpong.html rename : dom/base/test/iframe_messageChannel_post.html => dom/messagechannel/tests/iframe_messageChannel_post.html rename : dom/base/test/test_messageChannel.html => dom/messagechannel/tests/test_messageChannel.html rename : dom/base/test/test_messageChannel.xul => dom/messagechannel/tests/test_messageChannel.xul rename : dom/base/test/test_messageChannel_cloning.html => dom/messagechannel/tests/test_messageChannel_cloning.html rename : dom/base/test/test_messageChannel_pingpong.html => dom/messagechannel/tests/test_messageChannel_pingpong.html rename : dom/base/test/test_messageChannel_post.html => dom/messagechannel/tests/test_messageChannel_post.html rename : dom/base/test/test_messageChannel_pref.html => dom/messagechannel/tests/test_messageChannel_pref.html rename : dom/base/test/test_messageChannel_start.html => dom/messagechannel/tests/test_messageChannel_start.html rename : dom/base/test/test_messageChannel_transferable.html => dom/messagechannel/tests/test_messageChannel_transferable.html rename : dom/base/test/test_messageChannel_unshipped.html => dom/messagechannel/tests/test_messageChannel_unshipped.html
This commit is contained in:
Родитель
84d9d4e6f1
Коммит
8372e7d29d
|
@ -1,104 +0,0 @@
|
||||||
/* -*- 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 "MessageChannel.h"
|
|
||||||
|
|
||||||
#include "mozilla/Preferences.h"
|
|
||||||
#include "mozilla/dom/MessageChannelBinding.h"
|
|
||||||
#include "mozilla/dom/MessagePort.h"
|
|
||||||
#include "nsContentUtils.h"
|
|
||||||
#include "nsPIDOMWindow.h"
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
namespace dom {
|
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MessageChannel, mWindow, mPort1, mPort2)
|
|
||||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(MessageChannel)
|
|
||||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(MessageChannel)
|
|
||||||
|
|
||||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MessageChannel)
|
|
||||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
|
||||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
|
||||||
NS_INTERFACE_MAP_END
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
bool gPrefInitialized = false;
|
|
||||||
bool gPrefEnabled = false;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* static */ bool
|
|
||||||
MessageChannel::Enabled(JSContext* aCx, JSObject* aObj)
|
|
||||||
{
|
|
||||||
if (!gPrefInitialized) {
|
|
||||||
Preferences::AddBoolVarCache(&gPrefEnabled, "dom.messageChannel.enabled");
|
|
||||||
gPrefInitialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enabled by pref
|
|
||||||
if (gPrefEnabled) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Chrome callers are allowed.
|
|
||||||
if (nsContentUtils::ThreadsafeIsCallerChrome()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsCOMPtr<nsIPrincipal> principal = nsContentUtils::SubjectPrincipal();
|
|
||||||
MOZ_ASSERT(principal);
|
|
||||||
|
|
||||||
nsCOMPtr<nsIURI> uri;
|
|
||||||
if (NS_FAILED(principal->GetURI(getter_AddRefs(uri))) || !uri) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isResource = false;
|
|
||||||
if (NS_FAILED(uri->SchemeIs("resource", &isResource))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return isResource;
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageChannel::MessageChannel(nsPIDOMWindow* aWindow)
|
|
||||||
: mWindow(aWindow)
|
|
||||||
{
|
|
||||||
MOZ_COUNT_CTOR(MessageChannel);
|
|
||||||
|
|
||||||
mPort1 = new MessagePort(mWindow);
|
|
||||||
mPort2 = new MessagePort(mWindow);
|
|
||||||
|
|
||||||
mPort1->Entangle(mPort2);
|
|
||||||
mPort2->Entangle(mPort1);
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageChannel::~MessageChannel()
|
|
||||||
{
|
|
||||||
MOZ_COUNT_DTOR(MessageChannel);
|
|
||||||
}
|
|
||||||
|
|
||||||
JSObject*
|
|
||||||
MessageChannel::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
|
||||||
{
|
|
||||||
return MessageChannelBinding::Wrap(aCx, this, aGivenProto);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* static */ already_AddRefed<MessageChannel>
|
|
||||||
MessageChannel::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
|
|
||||||
if (!window) {
|
|
||||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsRefPtr<MessageChannel> channel = new MessageChannel(window);
|
|
||||||
return channel.forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace dom
|
|
||||||
} // namespace mozilla
|
|
|
@ -1,564 +0,0 @@
|
||||||
/* -*- 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 "MessagePort.h"
|
|
||||||
#include "MessageEvent.h"
|
|
||||||
#include "mozilla/dom/BlobBinding.h"
|
|
||||||
#include "mozilla/dom/Event.h"
|
|
||||||
#include "mozilla/dom/File.h"
|
|
||||||
#include "mozilla/dom/MessageChannel.h"
|
|
||||||
#include "mozilla/dom/MessagePortBinding.h"
|
|
||||||
#include "mozilla/dom/MessagePortList.h"
|
|
||||||
#include "mozilla/dom/StructuredCloneTags.h"
|
|
||||||
#include "nsContentUtils.h"
|
|
||||||
#include "nsGlobalWindow.h"
|
|
||||||
#include "nsPresContext.h"
|
|
||||||
#include "ScriptSettings.h"
|
|
||||||
|
|
||||||
#include "nsIDocument.h"
|
|
||||||
#include "nsIDOMFileList.h"
|
|
||||||
#include "nsIPresShell.h"
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
namespace dom {
|
|
||||||
|
|
||||||
class DispatchEventRunnable : public nsRunnable
|
|
||||||
{
|
|
||||||
friend class MessagePort;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit DispatchEventRunnable(MessagePort* aPort)
|
|
||||||
: mPort(aPort)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHOD
|
|
||||||
Run()
|
|
||||||
{
|
|
||||||
nsRefPtr<DispatchEventRunnable> mKungFuDeathGrip(this);
|
|
||||||
|
|
||||||
mPort->mDispatchRunnable = nullptr;
|
|
||||||
mPort->Dispatch();
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
nsRefPtr<MessagePort> mPort;
|
|
||||||
};
|
|
||||||
|
|
||||||
class PostMessageRunnable : public nsRunnable
|
|
||||||
{
|
|
||||||
friend class MessagePort;
|
|
||||||
|
|
||||||
public:
|
|
||||||
NS_DECL_NSIRUNNABLE
|
|
||||||
|
|
||||||
PostMessageRunnable()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
~PostMessageRunnable()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
JSAutoStructuredCloneBuffer& Buffer()
|
|
||||||
{
|
|
||||||
return mBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool StoreISupports(nsISupports* aSupports)
|
|
||||||
{
|
|
||||||
mSupportsArray.AppendElement(aSupports);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dispatch(MessagePort* aPort)
|
|
||||||
{
|
|
||||||
mPort = aPort;
|
|
||||||
NS_DispatchToCurrentThread(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
nsRefPtr<MessagePort> mPort;
|
|
||||||
JSAutoStructuredCloneBuffer mBuffer;
|
|
||||||
|
|
||||||
nsTArray<nsCOMPtr<nsISupports> > mSupportsArray;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
struct StructuredCloneInfo
|
|
||||||
{
|
|
||||||
PostMessageRunnable* mEvent;
|
|
||||||
MessagePort* mPort;
|
|
||||||
nsRefPtrHashtable<nsRefPtrHashKey<MessagePortBase>, MessagePortBase> mPorts;
|
|
||||||
};
|
|
||||||
|
|
||||||
static JSObject*
|
|
||||||
PostMessageReadStructuredClone(JSContext* cx,
|
|
||||||
JSStructuredCloneReader* reader,
|
|
||||||
uint32_t tag,
|
|
||||||
uint32_t data,
|
|
||||||
void* closure)
|
|
||||||
{
|
|
||||||
StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure);
|
|
||||||
NS_ASSERTION(scInfo, "Must have scInfo!");
|
|
||||||
|
|
||||||
if (tag == SCTAG_DOM_BLOB) {
|
|
||||||
NS_ASSERTION(!data, "Data should be empty");
|
|
||||||
|
|
||||||
// What we get back from the reader is a BlobImpl.
|
|
||||||
// From that we create a new File.
|
|
||||||
BlobImpl* blobImpl;
|
|
||||||
if (JS_ReadBytes(reader, &blobImpl, sizeof(blobImpl))) {
|
|
||||||
MOZ_ASSERT(blobImpl);
|
|
||||||
|
|
||||||
// nsRefPtr<File> needs to go out of scope before toObjectOrNull() is
|
|
||||||
// called because the static analysis thinks dereferencing XPCOM objects
|
|
||||||
// can GC (because in some cases it can!), and a return statement with a
|
|
||||||
// JSObject* type means that JSObject* is on the stack as a raw pointer
|
|
||||||
// while destructors are running.
|
|
||||||
JS::Rooted<JS::Value> val(cx);
|
|
||||||
{
|
|
||||||
nsRefPtr<Blob> blob = Blob::Create(scInfo->mPort->GetParentObject(),
|
|
||||||
blobImpl);
|
|
||||||
if (!ToJSValue(cx, blob, &val)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &val.toObject();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tag == SCTAG_DOM_FILELIST) {
|
|
||||||
NS_ASSERTION(!data, "Data should be empty");
|
|
||||||
|
|
||||||
nsISupports* supports;
|
|
||||||
if (JS_ReadBytes(reader, &supports, sizeof(supports))) {
|
|
||||||
JS::Rooted<JS::Value> val(cx);
|
|
||||||
if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, supports, &val))) {
|
|
||||||
return val.toObjectOrNull();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const JSStructuredCloneCallbacks* runtimeCallbacks =
|
|
||||||
js::GetContextStructuredCloneCallbacks(cx);
|
|
||||||
|
|
||||||
if (runtimeCallbacks) {
|
|
||||||
return runtimeCallbacks->read(cx, reader, tag, data, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
PostMessageWriteStructuredClone(JSContext* cx,
|
|
||||||
JSStructuredCloneWriter* writer,
|
|
||||||
JS::Handle<JSObject*> obj,
|
|
||||||
void *closure)
|
|
||||||
{
|
|
||||||
StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure);
|
|
||||||
NS_ASSERTION(scInfo, "Must have scInfo!");
|
|
||||||
|
|
||||||
// See if this is a File/Blob object.
|
|
||||||
{
|
|
||||||
Blob* blob = nullptr;
|
|
||||||
if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, obj, blob))) {
|
|
||||||
BlobImpl* blobImpl = blob->Impl();
|
|
||||||
if (JS_WriteUint32Pair(writer, SCTAG_DOM_BLOB, 0) &&
|
|
||||||
JS_WriteBytes(writer, &blobImpl, sizeof(blobImpl))) {
|
|
||||||
scInfo->mEvent->StoreISupports(blobImpl);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative;
|
|
||||||
nsContentUtils::XPConnect()->
|
|
||||||
GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wrappedNative));
|
|
||||||
if (wrappedNative) {
|
|
||||||
uint32_t scTag = 0;
|
|
||||||
nsISupports* supports = wrappedNative->Native();
|
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMFileList> list = do_QueryInterface(supports);
|
|
||||||
if (list) {
|
|
||||||
scTag = SCTAG_DOM_FILELIST;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scTag) {
|
|
||||||
return JS_WriteUint32Pair(writer, scTag, 0) &&
|
|
||||||
JS_WriteBytes(writer, &supports, sizeof(supports)) &&
|
|
||||||
scInfo->mEvent->StoreISupports(supports);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const JSStructuredCloneCallbacks* runtimeCallbacks =
|
|
||||||
js::GetContextStructuredCloneCallbacks(cx);
|
|
||||||
|
|
||||||
if (runtimeCallbacks) {
|
|
||||||
return runtimeCallbacks->write(cx, writer, obj, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
PostMessageReadTransferStructuredClone(JSContext* aCx,
|
|
||||||
JSStructuredCloneReader* reader,
|
|
||||||
uint32_t tag, void* data,
|
|
||||||
uint64_t unused,
|
|
||||||
void* aClosure,
|
|
||||||
JS::MutableHandle<JSObject*> returnObject)
|
|
||||||
{
|
|
||||||
StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(aClosure);
|
|
||||||
NS_ASSERTION(scInfo, "Must have scInfo!");
|
|
||||||
|
|
||||||
if (tag == SCTAG_DOM_MAP_MESSAGEPORT) {
|
|
||||||
MessagePort* port = static_cast<MessagePort*>(data);
|
|
||||||
port->BindToOwner(scInfo->mPort->GetOwner());
|
|
||||||
scInfo->mPorts.Put(port, nullptr);
|
|
||||||
|
|
||||||
JS::Rooted<JSObject*> obj(aCx, port->WrapObject(aCx, nullptr));
|
|
||||||
if (!obj || !JS_WrapObject(aCx, &obj)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT(port->GetOwner() == scInfo->mPort->GetOwner());
|
|
||||||
returnObject.set(obj);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
PostMessageTransferStructuredClone(JSContext* aCx,
|
|
||||||
JS::Handle<JSObject*> aObj,
|
|
||||||
void* aClosure,
|
|
||||||
uint32_t* aTag,
|
|
||||||
JS::TransferableOwnership* aOwnership,
|
|
||||||
void** aContent,
|
|
||||||
uint64_t *aExtraData)
|
|
||||||
{
|
|
||||||
StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(aClosure);
|
|
||||||
NS_ASSERTION(scInfo, "Must have scInfo!");
|
|
||||||
|
|
||||||
MessagePortBase *port = nullptr;
|
|
||||||
nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port);
|
|
||||||
if (NS_SUCCEEDED(rv)) {
|
|
||||||
nsRefPtr<MessagePortBase> newPort;
|
|
||||||
if (scInfo->mPorts.Get(port, getter_AddRefs(newPort))) {
|
|
||||||
// No duplicate.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
newPort = port->Clone();
|
|
||||||
scInfo->mPorts.Put(port, newPort);
|
|
||||||
|
|
||||||
*aTag = SCTAG_DOM_MAP_MESSAGEPORT;
|
|
||||||
*aOwnership = JS::SCTAG_TMO_CUSTOM;
|
|
||||||
*aContent = newPort;
|
|
||||||
*aExtraData = 0;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
PostMessageFreeTransferStructuredClone(uint32_t aTag, JS::TransferableOwnership aOwnership,
|
|
||||||
void* aData,
|
|
||||||
uint64_t aExtraData,
|
|
||||||
void* aClosure)
|
|
||||||
{
|
|
||||||
StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(aClosure);
|
|
||||||
NS_ASSERTION(scInfo, "Must have scInfo!");
|
|
||||||
|
|
||||||
if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) {
|
|
||||||
MOZ_ASSERT(aOwnership == JS::SCTAG_TMO_CUSTOM);
|
|
||||||
nsRefPtr<MessagePort> port(static_cast<MessagePort*>(aData));
|
|
||||||
scInfo->mPorts.Remove(port);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const JSStructuredCloneCallbacks kPostMessageCallbacks = {
|
|
||||||
PostMessageReadStructuredClone,
|
|
||||||
PostMessageWriteStructuredClone,
|
|
||||||
nullptr,
|
|
||||||
PostMessageReadTransferStructuredClone,
|
|
||||||
PostMessageTransferStructuredClone,
|
|
||||||
PostMessageFreeTransferStructuredClone
|
|
||||||
};
|
|
||||||
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
static PLDHashOperator
|
|
||||||
PopulateMessagePortList(MessagePortBase* aKey, MessagePortBase* aValue, void* aClosure)
|
|
||||||
{
|
|
||||||
nsTArray<nsRefPtr<MessagePortBase> > *array =
|
|
||||||
static_cast<nsTArray<nsRefPtr<MessagePortBase> > *>(aClosure);
|
|
||||||
|
|
||||||
array->AppendElement(aKey);
|
|
||||||
return PL_DHASH_NEXT;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
PostMessageRunnable::Run()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(mPort);
|
|
||||||
|
|
||||||
AutoJSAPI jsapi;
|
|
||||||
if (NS_WARN_IF(!jsapi.Init(mPort->GetParentObject()))) {
|
|
||||||
return NS_ERROR_UNEXPECTED;
|
|
||||||
}
|
|
||||||
JSContext* cx = jsapi.cx();
|
|
||||||
|
|
||||||
// Deserialize the structured clone data
|
|
||||||
JS::Rooted<JS::Value> messageData(cx);
|
|
||||||
StructuredCloneInfo scInfo;
|
|
||||||
scInfo.mEvent = this;
|
|
||||||
scInfo.mPort = mPort;
|
|
||||||
|
|
||||||
if (!mBuffer.read(cx, &messageData, &kPostMessageCallbacks, &scInfo)) {
|
|
||||||
return NS_ERROR_DOM_DATA_CLONE_ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the event
|
|
||||||
nsCOMPtr<mozilla::dom::EventTarget> eventTarget =
|
|
||||||
do_QueryInterface(mPort->GetOwner());
|
|
||||||
nsRefPtr<MessageEvent> event =
|
|
||||||
new MessageEvent(eventTarget, nullptr, nullptr);
|
|
||||||
|
|
||||||
event->InitMessageEvent(NS_LITERAL_STRING("message"), false /* non-bubbling */,
|
|
||||||
false /* cancelable */, messageData, EmptyString(),
|
|
||||||
EmptyString(), nullptr);
|
|
||||||
event->SetTrusted(true);
|
|
||||||
event->SetSource(mPort);
|
|
||||||
|
|
||||||
nsTArray<nsRefPtr<MessagePortBase> > ports;
|
|
||||||
scInfo.mPorts.EnumerateRead(PopulateMessagePortList, &ports);
|
|
||||||
event->SetPorts(new MessagePortList(static_cast<dom::Event*>(event.get()), ports));
|
|
||||||
|
|
||||||
bool status;
|
|
||||||
mPort->DispatchEvent(static_cast<dom::Event*>(event.get()), &status);
|
|
||||||
return status ? NS_OK : NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
MessagePortBase::MessagePortBase(nsPIDOMWindow* aWindow)
|
|
||||||
: DOMEventTargetHelper(aWindow)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
MessagePortBase::MessagePortBase()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_CLASS(MessagePort)
|
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MessagePort,
|
|
||||||
DOMEventTargetHelper)
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mEntangledPort)
|
|
||||||
|
|
||||||
// Custom unlink loop because this array contains nsRunnable objects
|
|
||||||
// which are not cycle colleactable.
|
|
||||||
while (!tmp->mMessageQueue.IsEmpty()) {
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageQueue[0]->mPort);
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageQueue[0]->mSupportsArray);
|
|
||||||
tmp->mMessageQueue.RemoveElementAt(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tmp->mDispatchRunnable) {
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDispatchRunnable->mPort);
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MessagePort,
|
|
||||||
DOMEventTargetHelper)
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEntangledPort)
|
|
||||||
|
|
||||||
// Custom unlink loop because this array contains nsRunnable objects
|
|
||||||
// which are not cycle colleactable.
|
|
||||||
for (uint32_t i = 0, len = tmp->mMessageQueue.Length(); i < len; ++i) {
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageQueue[i]->mPort);
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageQueue[i]->mSupportsArray);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tmp->mDispatchRunnable) {
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDispatchRunnable->mPort);
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
||||||
|
|
||||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MessagePort)
|
|
||||||
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
|
|
||||||
|
|
||||||
NS_IMPL_ADDREF_INHERITED(MessagePort, DOMEventTargetHelper)
|
|
||||||
NS_IMPL_RELEASE_INHERITED(MessagePort, DOMEventTargetHelper)
|
|
||||||
|
|
||||||
MessagePort::MessagePort(nsPIDOMWindow* aWindow)
|
|
||||||
: MessagePortBase(aWindow)
|
|
||||||
, mMessageQueueEnabled(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
MessagePort::~MessagePort()
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
JSObject*
|
|
||||||
MessagePort::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
|
||||||
{
|
|
||||||
return MessagePortBinding::Wrap(aCx, this, aGivenProto);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MessagePort::PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
|
||||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
|
||||||
ErrorResult& aRv)
|
|
||||||
{
|
|
||||||
nsRefPtr<PostMessageRunnable> event = new PostMessageRunnable();
|
|
||||||
|
|
||||||
// We *must* clone the data here, or the JS::Value could be modified
|
|
||||||
// by script
|
|
||||||
StructuredCloneInfo scInfo;
|
|
||||||
scInfo.mEvent = event;
|
|
||||||
scInfo.mPort = this;
|
|
||||||
|
|
||||||
JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue());
|
|
||||||
if (aTransferable.WasPassed()) {
|
|
||||||
const Sequence<JS::Value>& realTransferable = aTransferable.Value();
|
|
||||||
|
|
||||||
// The input sequence only comes from the generated bindings code, which
|
|
||||||
// ensures it is rooted.
|
|
||||||
JS::HandleValueArray elements =
|
|
||||||
JS::HandleValueArray::fromMarkedLocation(realTransferable.Length(),
|
|
||||||
realTransferable.Elements());
|
|
||||||
|
|
||||||
JSObject* array =
|
|
||||||
JS_NewArrayObject(aCx, elements);
|
|
||||||
if (!array) {
|
|
||||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
transferable.setObject(*array);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!event->Buffer().write(aCx, aMessage, transferable,
|
|
||||||
&kPostMessageCallbacks, &scInfo)) {
|
|
||||||
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mEntangledPort) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mEntangledPort->mMessageQueue.AppendElement(event);
|
|
||||||
mEntangledPort->Dispatch();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MessagePort::Start()
|
|
||||||
{
|
|
||||||
if (mMessageQueueEnabled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mMessageQueueEnabled = true;
|
|
||||||
Dispatch();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MessagePort::Dispatch()
|
|
||||||
{
|
|
||||||
if (!mMessageQueueEnabled || mMessageQueue.IsEmpty() || mDispatchRunnable) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsRefPtr<PostMessageRunnable> event = mMessageQueue.ElementAt(0);
|
|
||||||
mMessageQueue.RemoveElementAt(0);
|
|
||||||
|
|
||||||
event->Dispatch(this);
|
|
||||||
|
|
||||||
mDispatchRunnable = new DispatchEventRunnable(this);
|
|
||||||
NS_DispatchToCurrentThread(mDispatchRunnable);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MessagePort::Close()
|
|
||||||
{
|
|
||||||
if (!mEntangledPort) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This avoids loops.
|
|
||||||
nsRefPtr<MessagePort> port = mEntangledPort;
|
|
||||||
mEntangledPort = nullptr;
|
|
||||||
|
|
||||||
// Let's disentangle the 2 ports symmetrically.
|
|
||||||
port->Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
EventHandlerNonNull*
|
|
||||||
MessagePort::GetOnmessage()
|
|
||||||
{
|
|
||||||
if (NS_IsMainThread()) {
|
|
||||||
return GetEventHandler(nsGkAtoms::onmessage, EmptyString());
|
|
||||||
}
|
|
||||||
return GetEventHandler(nullptr, NS_LITERAL_STRING("message"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MessagePort::SetOnmessage(EventHandlerNonNull* aCallback)
|
|
||||||
{
|
|
||||||
if (NS_IsMainThread()) {
|
|
||||||
SetEventHandler(nsGkAtoms::onmessage, EmptyString(), aCallback);
|
|
||||||
} else {
|
|
||||||
SetEventHandler(nullptr, NS_LITERAL_STRING("message"), aCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
// When using onmessage, the call to start() is implied.
|
|
||||||
Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MessagePort::Entangle(MessagePort* aMessagePort)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(aMessagePort);
|
|
||||||
MOZ_ASSERT(aMessagePort != this);
|
|
||||||
|
|
||||||
Close();
|
|
||||||
|
|
||||||
mEntangledPort = aMessagePort;
|
|
||||||
}
|
|
||||||
|
|
||||||
already_AddRefed<MessagePortBase>
|
|
||||||
MessagePort::Clone()
|
|
||||||
{
|
|
||||||
nsRefPtr<MessagePort> newPort = new MessagePort(nullptr);
|
|
||||||
|
|
||||||
// Move all the events in the port message queue of original port.
|
|
||||||
newPort->mMessageQueue.SwapElements(mMessageQueue);
|
|
||||||
|
|
||||||
if (mEntangledPort) {
|
|
||||||
nsRefPtr<MessagePort> port = mEntangledPort;
|
|
||||||
mEntangledPort = nullptr;
|
|
||||||
|
|
||||||
newPort->Entangle(port);
|
|
||||||
port->Entangle(newPort);
|
|
||||||
}
|
|
||||||
|
|
||||||
return newPort.forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace dom
|
|
||||||
} // namespace mozilla
|
|
|
@ -1,115 +0,0 @@
|
||||||
/* -*- 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_MessagePort_h
|
|
||||||
#define mozilla_dom_MessagePort_h
|
|
||||||
|
|
||||||
#include "mozilla/Attributes.h"
|
|
||||||
#include "mozilla/DOMEventTargetHelper.h"
|
|
||||||
|
|
||||||
class nsPIDOMWindow;
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
namespace dom {
|
|
||||||
|
|
||||||
class DispatchEventRunnable;
|
|
||||||
class PostMessageRunnable;
|
|
||||||
|
|
||||||
class MessagePortBase : public DOMEventTargetHelper
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
explicit MessagePortBase(nsPIDOMWindow* aWindow);
|
|
||||||
MessagePortBase();
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
virtual void
|
|
||||||
PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
|
||||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
|
||||||
ErrorResult& aRv) = 0;
|
|
||||||
|
|
||||||
virtual void
|
|
||||||
Start() = 0;
|
|
||||||
|
|
||||||
virtual void
|
|
||||||
Close() = 0;
|
|
||||||
|
|
||||||
// The 'message' event handler has to call |Start()| method, so we
|
|
||||||
// cannot use IMPL_EVENT_HANDLER macro here.
|
|
||||||
virtual EventHandlerNonNull*
|
|
||||||
GetOnmessage() = 0;
|
|
||||||
|
|
||||||
virtual void
|
|
||||||
SetOnmessage(EventHandlerNonNull* aCallback) = 0;
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
virtual already_AddRefed<MessagePortBase>
|
|
||||||
Clone() = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class MessagePort final : public MessagePortBase
|
|
||||||
{
|
|
||||||
friend class DispatchEventRunnable;
|
|
||||||
friend class PostMessageRunnable;
|
|
||||||
|
|
||||||
public:
|
|
||||||
NS_DECL_ISUPPORTS_INHERITED
|
|
||||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MessagePort,
|
|
||||||
DOMEventTargetHelper)
|
|
||||||
|
|
||||||
explicit MessagePort(nsPIDOMWindow* aWindow);
|
|
||||||
|
|
||||||
virtual JSObject*
|
|
||||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
|
||||||
|
|
||||||
virtual void
|
|
||||||
PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
|
||||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
|
||||||
ErrorResult& aRv) override;
|
|
||||||
|
|
||||||
virtual void
|
|
||||||
Start() override;
|
|
||||||
|
|
||||||
virtual void
|
|
||||||
Close() override;
|
|
||||||
|
|
||||||
virtual EventHandlerNonNull*
|
|
||||||
GetOnmessage() override;
|
|
||||||
|
|
||||||
virtual void
|
|
||||||
SetOnmessage(EventHandlerNonNull* aCallback) override;
|
|
||||||
|
|
||||||
// Non WebIDL methods
|
|
||||||
|
|
||||||
// This method entangles this MessagePort with another one.
|
|
||||||
// If it is already entangled, it's disentangled first and enatangle to the
|
|
||||||
// new one.
|
|
||||||
void
|
|
||||||
Entangle(MessagePort* aMessagePort);
|
|
||||||
|
|
||||||
virtual already_AddRefed<MessagePortBase>
|
|
||||||
Clone() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
~MessagePort();
|
|
||||||
|
|
||||||
// Dispatch events from the Message Queue using a nsRunnable.
|
|
||||||
void Dispatch();
|
|
||||||
|
|
||||||
nsRefPtr<DispatchEventRunnable> mDispatchRunnable;
|
|
||||||
|
|
||||||
nsRefPtr<MessagePort> mEntangledPort;
|
|
||||||
|
|
||||||
nsTArray<nsRefPtr<PostMessageRunnable> > mMessageQueue;
|
|
||||||
bool mMessageQueueEnabled;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace dom
|
|
||||||
} // namespace mozilla
|
|
||||||
|
|
||||||
#endif // mozilla_dom_MessagePort_h
|
|
|
@ -111,7 +111,7 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(NodeInfo)
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_0(NodeInfo)
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_0(NodeInfo)
|
||||||
|
|
||||||
static const char* kNSURIs[] = {
|
static const char* kNodeInfoNSURIs[] = {
|
||||||
" ([none])",
|
" ([none])",
|
||||||
" (xmlns)",
|
" (xmlns)",
|
||||||
" (xml)",
|
" (xml)",
|
||||||
|
@ -129,8 +129,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(NodeInfo)
|
||||||
char name[72];
|
char name[72];
|
||||||
uint32_t nsid = tmp->NamespaceID();
|
uint32_t nsid = tmp->NamespaceID();
|
||||||
nsAtomCString localName(tmp->NameAtom());
|
nsAtomCString localName(tmp->NameAtom());
|
||||||
if (nsid < ArrayLength(kNSURIs)) {
|
if (nsid < ArrayLength(kNodeInfoNSURIs)) {
|
||||||
PR_snprintf(name, sizeof(name), "NodeInfo%s %s", kNSURIs[nsid],
|
PR_snprintf(name, sizeof(name), "NodeInfo%s %s", kNodeInfoNSURIs[nsid],
|
||||||
localName.get());
|
localName.get());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -0,0 +1,390 @@
|
||||||
|
/* -*- 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 "PostMessageEvent.h"
|
||||||
|
|
||||||
|
#include "MessageEvent.h"
|
||||||
|
#include "mozilla/dom/BlobBinding.h"
|
||||||
|
#include "mozilla/dom/MessagePort.h"
|
||||||
|
#include "mozilla/dom/MessagePortBinding.h"
|
||||||
|
#include "mozilla/dom/PMessagePort.h"
|
||||||
|
#include "mozilla/dom/StructuredCloneTags.h"
|
||||||
|
#include "mozilla/EventDispatcher.h"
|
||||||
|
#include "nsGlobalWindow.h"
|
||||||
|
#include "nsIPresShell.h"
|
||||||
|
#include "nsIPrincipal.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct StructuredCloneInfo
|
||||||
|
{
|
||||||
|
PostMessageEvent* event;
|
||||||
|
bool subsumes;
|
||||||
|
nsPIDOMWindow* window;
|
||||||
|
|
||||||
|
// This hashtable contains the transferred ports - used to avoid duplicates.
|
||||||
|
nsTArray<nsRefPtr<MessagePortBase>> transferredPorts;
|
||||||
|
|
||||||
|
// This array is populated when the ports are cloned.
|
||||||
|
nsTArray<nsRefPtr<MessagePortBase>> clonedPorts;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
const JSStructuredCloneCallbacks PostMessageEvent::sPostMessageCallbacks = {
|
||||||
|
PostMessageEvent::ReadStructuredClone,
|
||||||
|
PostMessageEvent::WriteStructuredClone,
|
||||||
|
nullptr,
|
||||||
|
PostMessageEvent::ReadTransferStructuredClone,
|
||||||
|
PostMessageEvent::TransferStructuredClone,
|
||||||
|
PostMessageEvent::FreeTransferStructuredClone
|
||||||
|
};
|
||||||
|
|
||||||
|
/* static */ JSObject*
|
||||||
|
PostMessageEvent::ReadStructuredClone(JSContext* cx,
|
||||||
|
JSStructuredCloneReader* reader,
|
||||||
|
uint32_t tag,
|
||||||
|
uint32_t data,
|
||||||
|
void* closure)
|
||||||
|
{
|
||||||
|
StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure);
|
||||||
|
NS_ASSERTION(scInfo, "Must have scInfo!");
|
||||||
|
|
||||||
|
if (tag == SCTAG_DOM_BLOB) {
|
||||||
|
NS_ASSERTION(!data, "Data should be empty");
|
||||||
|
|
||||||
|
// What we get back from the reader is a BlobImpl.
|
||||||
|
// From that we create a new File.
|
||||||
|
BlobImpl* blobImpl;
|
||||||
|
if (JS_ReadBytes(reader, &blobImpl, sizeof(blobImpl))) {
|
||||||
|
MOZ_ASSERT(blobImpl);
|
||||||
|
|
||||||
|
// nsRefPtr<File> needs to go out of scope before toObjectOrNull() is
|
||||||
|
// called because the static analysis thinks dereferencing XPCOM objects
|
||||||
|
// can GC (because in some cases it can!), and a return statement with a
|
||||||
|
// JSObject* type means that JSObject* is on the stack as a raw pointer
|
||||||
|
// while destructors are running.
|
||||||
|
JS::Rooted<JS::Value> val(cx);
|
||||||
|
{
|
||||||
|
nsRefPtr<Blob> blob = Blob::Create(scInfo->window, blobImpl);
|
||||||
|
if (!ToJSValue(cx, blob, &val)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &val.toObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tag == SCTAG_DOM_FILELIST) {
|
||||||
|
NS_ASSERTION(!data, "Data should be empty");
|
||||||
|
|
||||||
|
nsISupports* supports;
|
||||||
|
if (JS_ReadBytes(reader, &supports, sizeof(supports))) {
|
||||||
|
JS::Rooted<JS::Value> val(cx);
|
||||||
|
if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, supports, &val))) {
|
||||||
|
return val.toObjectOrNull();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const JSStructuredCloneCallbacks* runtimeCallbacks =
|
||||||
|
js::GetContextStructuredCloneCallbacks(cx);
|
||||||
|
|
||||||
|
if (runtimeCallbacks) {
|
||||||
|
return runtimeCallbacks->read(cx, reader, tag, data, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */ bool
|
||||||
|
PostMessageEvent::WriteStructuredClone(JSContext* cx,
|
||||||
|
JSStructuredCloneWriter* writer,
|
||||||
|
JS::Handle<JSObject*> obj,
|
||||||
|
void *closure)
|
||||||
|
{
|
||||||
|
StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure);
|
||||||
|
NS_ASSERTION(scInfo, "Must have scInfo!");
|
||||||
|
|
||||||
|
// See if this is a File/Blob object.
|
||||||
|
{
|
||||||
|
Blob* blob = nullptr;
|
||||||
|
if (scInfo->subsumes && NS_SUCCEEDED(UNWRAP_OBJECT(Blob, obj, blob))) {
|
||||||
|
BlobImpl* blobImpl = blob->Impl();
|
||||||
|
if (JS_WriteUint32Pair(writer, SCTAG_DOM_BLOB, 0) &&
|
||||||
|
JS_WriteBytes(writer, &blobImpl, sizeof(blobImpl))) {
|
||||||
|
scInfo->event->StoreISupports(blobImpl);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative;
|
||||||
|
nsContentUtils::XPConnect()->
|
||||||
|
GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wrappedNative));
|
||||||
|
if (wrappedNative) {
|
||||||
|
uint32_t scTag = 0;
|
||||||
|
nsISupports* supports = wrappedNative->Native();
|
||||||
|
|
||||||
|
nsCOMPtr<nsIDOMFileList> list = do_QueryInterface(supports);
|
||||||
|
if (list && scInfo->subsumes)
|
||||||
|
scTag = SCTAG_DOM_FILELIST;
|
||||||
|
|
||||||
|
if (scTag)
|
||||||
|
return JS_WriteUint32Pair(writer, scTag, 0) &&
|
||||||
|
JS_WriteBytes(writer, &supports, sizeof(supports)) &&
|
||||||
|
scInfo->event->StoreISupports(supports);
|
||||||
|
}
|
||||||
|
|
||||||
|
const JSStructuredCloneCallbacks* runtimeCallbacks =
|
||||||
|
js::GetContextStructuredCloneCallbacks(cx);
|
||||||
|
|
||||||
|
if (runtimeCallbacks) {
|
||||||
|
return runtimeCallbacks->write(cx, writer, obj, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */ bool
|
||||||
|
PostMessageEvent::ReadTransferStructuredClone(JSContext* aCx,
|
||||||
|
JSStructuredCloneReader* reader,
|
||||||
|
uint32_t tag, void* aData,
|
||||||
|
uint64_t aExtraData,
|
||||||
|
void* aClosure,
|
||||||
|
JS::MutableHandle<JSObject*> returnObject)
|
||||||
|
{
|
||||||
|
StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(aClosure);
|
||||||
|
NS_ASSERTION(scInfo, "Must have scInfo!");
|
||||||
|
|
||||||
|
if (tag == SCTAG_DOM_MAP_MESSAGEPORT) {
|
||||||
|
MOZ_ASSERT(!aData);
|
||||||
|
// aExtraData is the index of this port identifier.
|
||||||
|
ErrorResult rv;
|
||||||
|
nsRefPtr<MessagePort> port =
|
||||||
|
MessagePort::Create(scInfo->window,
|
||||||
|
scInfo->event->GetPortIdentifier(aExtraData),
|
||||||
|
rv);
|
||||||
|
if (NS_WARN_IF(rv.Failed())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
scInfo->clonedPorts.AppendElement(port);
|
||||||
|
|
||||||
|
JS::Rooted<JS::Value> value(aCx);
|
||||||
|
if (!GetOrCreateDOMReflector(aCx, port, &value)) {
|
||||||
|
JS_ClearPendingException(aCx);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
returnObject.set(&value.toObject());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */ bool
|
||||||
|
PostMessageEvent::TransferStructuredClone(JSContext* aCx,
|
||||||
|
JS::Handle<JSObject*> aObj,
|
||||||
|
void* aClosure,
|
||||||
|
uint32_t* aTag,
|
||||||
|
JS::TransferableOwnership* aOwnership,
|
||||||
|
void** aContent,
|
||||||
|
uint64_t* aExtraData)
|
||||||
|
{
|
||||||
|
StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(aClosure);
|
||||||
|
NS_ASSERTION(scInfo, "Must have scInfo!");
|
||||||
|
|
||||||
|
MessagePortBase* port = nullptr;
|
||||||
|
nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port);
|
||||||
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
if (scInfo->transferredPorts.Contains(port)) {
|
||||||
|
// No duplicates.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We use aExtraData to store the index of this new port identifier.
|
||||||
|
MessagePortIdentifier* identifier =
|
||||||
|
scInfo->event->NewPortIdentifier(aExtraData);
|
||||||
|
|
||||||
|
if (!port->CloneAndDisentangle(*identifier)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
scInfo->transferredPorts.AppendElement(port);
|
||||||
|
|
||||||
|
*aTag = SCTAG_DOM_MAP_MESSAGEPORT;
|
||||||
|
*aOwnership = JS::SCTAG_TMO_CUSTOM;
|
||||||
|
*aContent = nullptr;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */ void
|
||||||
|
PostMessageEvent::FreeTransferStructuredClone(uint32_t aTag,
|
||||||
|
JS::TransferableOwnership aOwnership,
|
||||||
|
void *aContent,
|
||||||
|
uint64_t aExtraData,
|
||||||
|
void* aClosure)
|
||||||
|
{
|
||||||
|
// Nothing to do.
|
||||||
|
}
|
||||||
|
|
||||||
|
PostMessageEvent::PostMessageEvent(nsGlobalWindow* aSource,
|
||||||
|
const nsAString& aCallerOrigin,
|
||||||
|
nsGlobalWindow* aTargetWindow,
|
||||||
|
nsIPrincipal* aProvidedPrincipal,
|
||||||
|
bool aTrustedCaller)
|
||||||
|
: mSource(aSource),
|
||||||
|
mCallerOrigin(aCallerOrigin),
|
||||||
|
mTargetWindow(aTargetWindow),
|
||||||
|
mProvidedPrincipal(aProvidedPrincipal),
|
||||||
|
mTrustedCaller(aTrustedCaller)
|
||||||
|
{
|
||||||
|
MOZ_COUNT_CTOR(PostMessageEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
PostMessageEvent::~PostMessageEvent()
|
||||||
|
{
|
||||||
|
MOZ_COUNT_DTOR(PostMessageEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
const MessagePortIdentifier&
|
||||||
|
PostMessageEvent::GetPortIdentifier(uint64_t aId)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aId < mPortIdentifiers.Length());
|
||||||
|
return mPortIdentifiers[aId];
|
||||||
|
}
|
||||||
|
|
||||||
|
MessagePortIdentifier*
|
||||||
|
PostMessageEvent::NewPortIdentifier(uint64_t* aPosition)
|
||||||
|
{
|
||||||
|
*aPosition = mPortIdentifiers.Length();
|
||||||
|
return mPortIdentifiers.AppendElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
PostMessageEvent::Run()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mTargetWindow->IsOuterWindow(),
|
||||||
|
"should have been passed an outer window!");
|
||||||
|
MOZ_ASSERT(!mSource || mSource->IsOuterWindow(),
|
||||||
|
"should have been passed an outer window!");
|
||||||
|
|
||||||
|
AutoJSAPI jsapi;
|
||||||
|
jsapi.Init();
|
||||||
|
JSContext* cx = jsapi.cx();
|
||||||
|
|
||||||
|
// If we bailed before this point we're going to leak mMessage, but
|
||||||
|
// that's probably better than crashing.
|
||||||
|
|
||||||
|
nsRefPtr<nsGlobalWindow> targetWindow;
|
||||||
|
if (mTargetWindow->IsClosedOrClosing() ||
|
||||||
|
!(targetWindow = mTargetWindow->GetCurrentInnerWindowInternal()) ||
|
||||||
|
targetWindow->IsClosedOrClosing())
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
|
MOZ_ASSERT(targetWindow->IsInnerWindow(),
|
||||||
|
"we ordered an inner window!");
|
||||||
|
JSAutoCompartment ac(cx, targetWindow->GetWrapperPreserveColor());
|
||||||
|
|
||||||
|
// Ensure that any origin which might have been provided is the origin of this
|
||||||
|
// window's document. Note that we do this *now* instead of when postMessage
|
||||||
|
// is called because the target window might have been navigated to a
|
||||||
|
// different location between then and now. If this check happened when
|
||||||
|
// postMessage was called, it would be fairly easy for a malicious webpage to
|
||||||
|
// intercept messages intended for another site by carefully timing navigation
|
||||||
|
// of the target window so it changed location after postMessage but before
|
||||||
|
// now.
|
||||||
|
if (mProvidedPrincipal) {
|
||||||
|
// Get the target's origin either from its principal or, in the case the
|
||||||
|
// principal doesn't carry a URI (e.g. the system principal), the target's
|
||||||
|
// document.
|
||||||
|
nsIPrincipal* targetPrin = targetWindow->GetPrincipal();
|
||||||
|
if (NS_WARN_IF(!targetPrin))
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
|
// Note: This is contrary to the spec with respect to file: URLs, which
|
||||||
|
// the spec groups into a single origin, but given we intentionally
|
||||||
|
// don't do that in other places it seems better to hold the line for
|
||||||
|
// now. Long-term, we want HTML5 to address this so that we can
|
||||||
|
// be compliant while being safer.
|
||||||
|
if (!targetPrin->Equals(mProvidedPrincipal)) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deserialize the structured clone data
|
||||||
|
JS::Rooted<JS::Value> messageData(cx);
|
||||||
|
StructuredCloneInfo scInfo;
|
||||||
|
scInfo.event = this;
|
||||||
|
scInfo.window = targetWindow;
|
||||||
|
|
||||||
|
if (!mBuffer.read(cx, &messageData, &sPostMessageCallbacks, &scInfo)) {
|
||||||
|
return NS_ERROR_DOM_DATA_CLONE_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the event
|
||||||
|
nsCOMPtr<mozilla::dom::EventTarget> eventTarget =
|
||||||
|
do_QueryInterface(static_cast<nsPIDOMWindow*>(targetWindow.get()));
|
||||||
|
nsRefPtr<MessageEvent> event =
|
||||||
|
new MessageEvent(eventTarget, nullptr, nullptr);
|
||||||
|
|
||||||
|
event->InitMessageEvent(NS_LITERAL_STRING("message"), false /*non-bubbling */,
|
||||||
|
false /*cancelable */, messageData, mCallerOrigin,
|
||||||
|
EmptyString(), mSource);
|
||||||
|
|
||||||
|
event->SetPorts(new MessagePortList(static_cast<dom::Event*>(event.get()),
|
||||||
|
scInfo.clonedPorts));
|
||||||
|
|
||||||
|
// We can't simply call dispatchEvent on the window because doing so ends
|
||||||
|
// up flipping the trusted bit on the event, and we don't want that to
|
||||||
|
// happen because then untrusted content can call postMessage on a chrome
|
||||||
|
// window if it can get a reference to it.
|
||||||
|
|
||||||
|
nsIPresShell *shell = targetWindow->GetExtantDoc()->GetShell();
|
||||||
|
nsRefPtr<nsPresContext> presContext;
|
||||||
|
if (shell)
|
||||||
|
presContext = shell->GetPresContext();
|
||||||
|
|
||||||
|
event->SetTrusted(mTrustedCaller);
|
||||||
|
WidgetEvent* internalEvent = event->GetInternalNSEvent();
|
||||||
|
|
||||||
|
nsEventStatus status = nsEventStatus_eIgnore;
|
||||||
|
EventDispatcher::Dispatch(static_cast<nsPIDOMWindow*>(mTargetWindow),
|
||||||
|
presContext,
|
||||||
|
internalEvent,
|
||||||
|
static_cast<dom::Event*>(event.get()),
|
||||||
|
&status);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
PostMessageEvent::Write(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||||
|
JS::Handle<JS::Value> aTransfer, bool aSubsumes,
|
||||||
|
nsPIDOMWindow* aWindow)
|
||||||
|
{
|
||||||
|
// We *must* clone the data here, or the JS::Value could be modified
|
||||||
|
// by script
|
||||||
|
StructuredCloneInfo scInfo;
|
||||||
|
scInfo.event = this;
|
||||||
|
scInfo.window = aWindow;
|
||||||
|
scInfo.subsumes = aSubsumes;
|
||||||
|
|
||||||
|
return mBuffer.write(aCx, aMessage, aTransfer, &sPostMessageCallbacks,
|
||||||
|
&scInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // dom namespace
|
||||||
|
} // mozilla namespace
|
|
@ -0,0 +1,108 @@
|
||||||
|
/* -*- 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_PostMessageEvent_h
|
||||||
|
#define mozilla_dom_PostMessageEvent_h
|
||||||
|
|
||||||
|
#include "js/StructuredClone.h"
|
||||||
|
#include "nsCOMPtr.h"
|
||||||
|
#include "nsRefPtr.h"
|
||||||
|
#include "nsTArray.h"
|
||||||
|
|
||||||
|
class nsGlobalWindow;
|
||||||
|
class nsIPrincipal;
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
class MessagePortBase;
|
||||||
|
class MessagePortIdentifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class used to represent events generated by calls to Window.postMessage,
|
||||||
|
* which asynchronously creates and dispatches events.
|
||||||
|
*/
|
||||||
|
class PostMessageEvent final : public nsRunnable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NS_DECL_NSIRUNNABLE
|
||||||
|
|
||||||
|
PostMessageEvent(nsGlobalWindow* aSource,
|
||||||
|
const nsAString& aCallerOrigin,
|
||||||
|
nsGlobalWindow* aTargetWindow,
|
||||||
|
nsIPrincipal* aProvidedPrincipal,
|
||||||
|
bool aTrustedCaller);
|
||||||
|
|
||||||
|
bool Write(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||||
|
JS::Handle<JS::Value> aTransfer, bool aSubsumes,
|
||||||
|
nsPIDOMWindow* aWindow);
|
||||||
|
|
||||||
|
private:
|
||||||
|
~PostMessageEvent();
|
||||||
|
|
||||||
|
const MessagePortIdentifier& GetPortIdentifier(uint64_t aId);
|
||||||
|
|
||||||
|
MessagePortIdentifier* NewPortIdentifier(uint64_t* aPosition);
|
||||||
|
|
||||||
|
bool StoreISupports(nsISupports* aSupports)
|
||||||
|
{
|
||||||
|
mSupportsArray.AppendElement(aSupports);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSObject*
|
||||||
|
ReadStructuredClone(JSContext* cx,
|
||||||
|
JSStructuredCloneReader* reader,
|
||||||
|
uint32_t tag,
|
||||||
|
uint32_t data,
|
||||||
|
void* closure);
|
||||||
|
|
||||||
|
static bool
|
||||||
|
WriteStructuredClone(JSContext* cx,
|
||||||
|
JSStructuredCloneWriter* writer,
|
||||||
|
JS::Handle<JSObject*> obj,
|
||||||
|
void *closure);
|
||||||
|
|
||||||
|
static bool
|
||||||
|
ReadTransferStructuredClone(JSContext* aCx,
|
||||||
|
JSStructuredCloneReader* reader,
|
||||||
|
uint32_t tag, void* aData,
|
||||||
|
uint64_t aExtraData,
|
||||||
|
void* aClosure,
|
||||||
|
JS::MutableHandle<JSObject*> returnObject);
|
||||||
|
|
||||||
|
static bool
|
||||||
|
TransferStructuredClone(JSContext* aCx,
|
||||||
|
JS::Handle<JSObject*> aObj,
|
||||||
|
void* aClosure,
|
||||||
|
uint32_t* aTag,
|
||||||
|
JS::TransferableOwnership* aOwnership,
|
||||||
|
void** aContent,
|
||||||
|
uint64_t* aExtraData);
|
||||||
|
|
||||||
|
static void
|
||||||
|
FreeTransferStructuredClone(uint32_t aTag,
|
||||||
|
JS::TransferableOwnership aOwnership,
|
||||||
|
void *aContent,
|
||||||
|
uint64_t aExtraData,
|
||||||
|
void* aClosure);
|
||||||
|
|
||||||
|
static const JSStructuredCloneCallbacks sPostMessageCallbacks;
|
||||||
|
|
||||||
|
JSAutoStructuredCloneBuffer mBuffer;
|
||||||
|
nsRefPtr<nsGlobalWindow> mSource;
|
||||||
|
nsString mCallerOrigin;
|
||||||
|
nsRefPtr<nsGlobalWindow> mTargetWindow;
|
||||||
|
nsCOMPtr<nsIPrincipal> mProvidedPrincipal;
|
||||||
|
bool mTrustedCaller;
|
||||||
|
nsTArray<nsCOMPtr<nsISupports>> mSupportsArray;
|
||||||
|
nsTArray<MessagePortIdentifier> mPortIdentifiers;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // dom namespace
|
||||||
|
} // mozilla namespace
|
||||||
|
|
||||||
|
#endif // mozilla_dom_PostMessageEvent_h
|
|
@ -7,6 +7,7 @@
|
||||||
#include "ProcessGlobal.h"
|
#include "ProcessGlobal.h"
|
||||||
|
|
||||||
#include "nsContentCID.h"
|
#include "nsContentCID.h"
|
||||||
|
#include "nsDOMClassInfoID.h"
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
using namespace mozilla::dom;
|
using namespace mozilla::dom;
|
||||||
|
|
|
@ -179,9 +179,6 @@ EXPORTS.mozilla.dom += [
|
||||||
'ImageEncoder.h',
|
'ImageEncoder.h',
|
||||||
'ImportManager.h',
|
'ImportManager.h',
|
||||||
'Link.h',
|
'Link.h',
|
||||||
'MessageChannel.h',
|
|
||||||
'MessagePort.h',
|
|
||||||
'MessagePortList.h',
|
|
||||||
'NameSpaceConstants.h',
|
'NameSpaceConstants.h',
|
||||||
'Navigator.h',
|
'Navigator.h',
|
||||||
'NodeInfo.h',
|
'NodeInfo.h',
|
||||||
|
@ -237,8 +234,6 @@ UNIFIED_SOURCES += [
|
||||||
'ImageEncoder.cpp',
|
'ImageEncoder.cpp',
|
||||||
'ImportManager.cpp',
|
'ImportManager.cpp',
|
||||||
'Link.cpp',
|
'Link.cpp',
|
||||||
'MessageChannel.cpp',
|
|
||||||
'MessagePortList.cpp',
|
|
||||||
'MultipartBlobImpl.cpp',
|
'MultipartBlobImpl.cpp',
|
||||||
'Navigator.cpp',
|
'Navigator.cpp',
|
||||||
'NodeInfo.cpp',
|
'NodeInfo.cpp',
|
||||||
|
@ -329,6 +324,7 @@ UNIFIED_SOURCES += [
|
||||||
'PerformanceMark.cpp',
|
'PerformanceMark.cpp',
|
||||||
'PerformanceMeasure.cpp',
|
'PerformanceMeasure.cpp',
|
||||||
'PerformanceResourceTiming.cpp',
|
'PerformanceResourceTiming.cpp',
|
||||||
|
'PostMessageEvent.cpp',
|
||||||
'ProcessGlobal.cpp',
|
'ProcessGlobal.cpp',
|
||||||
'ResponsiveImageSelector.cpp',
|
'ResponsiveImageSelector.cpp',
|
||||||
'SameProcessMessageQueue.cpp',
|
'SameProcessMessageQueue.cpp',
|
||||||
|
@ -353,8 +349,6 @@ if CONFIG['MOZ_WEBRTC']:
|
||||||
|
|
||||||
# these files couldn't be in UNIFIED_SOURCES for now for reasons given below:
|
# these files couldn't be in UNIFIED_SOURCES for now for reasons given below:
|
||||||
SOURCES += [
|
SOURCES += [
|
||||||
# this file doesn't like windows.h
|
|
||||||
'MessagePort.cpp',
|
|
||||||
# Because of OS X headers.
|
# Because of OS X headers.
|
||||||
'nsContentUtils.cpp',
|
'nsContentUtils.cpp',
|
||||||
# this file doesn't like windows.h
|
# this file doesn't like windows.h
|
||||||
|
|
|
@ -218,6 +218,7 @@ nsIPrincipal *nsContentUtils::sNullSubjectPrincipal;
|
||||||
nsIParserService *nsContentUtils::sParserService = nullptr;
|
nsIParserService *nsContentUtils::sParserService = nullptr;
|
||||||
nsNameSpaceManager *nsContentUtils::sNameSpaceManager;
|
nsNameSpaceManager *nsContentUtils::sNameSpaceManager;
|
||||||
nsIIOService *nsContentUtils::sIOService;
|
nsIIOService *nsContentUtils::sIOService;
|
||||||
|
nsIUUIDGenerator *nsContentUtils::sUUIDGenerator;
|
||||||
nsIConsoleService *nsContentUtils::sConsoleService;
|
nsIConsoleService *nsContentUtils::sConsoleService;
|
||||||
nsDataHashtable<nsISupportsHashKey, EventNameMapping>* nsContentUtils::sAtomEventTable = nullptr;
|
nsDataHashtable<nsISupportsHashKey, EventNameMapping>* nsContentUtils::sAtomEventTable = nullptr;
|
||||||
nsDataHashtable<nsStringHashKey, EventNameMapping>* nsContentUtils::sStringEventTable = nullptr;
|
nsDataHashtable<nsStringHashKey, EventNameMapping>* nsContentUtils::sStringEventTable = nullptr;
|
||||||
|
@ -551,6 +552,13 @@ nsContentUtils::Init()
|
||||||
|
|
||||||
Element::InitCCCallbacks();
|
Element::InitCCCallbacks();
|
||||||
|
|
||||||
|
nsCOMPtr<nsIUUIDGenerator> uuidGenerator =
|
||||||
|
do_GetService("@mozilla.org/uuid-generator;1", &rv);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
uuidGenerator.forget(&sUUIDGenerator);
|
||||||
|
|
||||||
sInitialized = true;
|
sInitialized = true;
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -1803,6 +1811,7 @@ nsContentUtils::Shutdown()
|
||||||
NS_IF_RELEASE(sNullSubjectPrincipal);
|
NS_IF_RELEASE(sNullSubjectPrincipal);
|
||||||
NS_IF_RELEASE(sParserService);
|
NS_IF_RELEASE(sParserService);
|
||||||
NS_IF_RELEASE(sIOService);
|
NS_IF_RELEASE(sIOService);
|
||||||
|
NS_IF_RELEASE(sUUIDGenerator);
|
||||||
NS_IF_RELEASE(sLineBreaker);
|
NS_IF_RELEASE(sLineBreaker);
|
||||||
NS_IF_RELEASE(sWordBreaker);
|
NS_IF_RELEASE(sWordBreaker);
|
||||||
NS_IF_RELEASE(sBidiKeyboard);
|
NS_IF_RELEASE(sBidiKeyboard);
|
||||||
|
@ -7150,6 +7159,19 @@ nsContentUtils::IsJavascriptMIMEType(const nsAString& aMIMEType)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsContentUtils::GenerateUUIDInPlace(nsID& aUUID)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(sUUIDGenerator);
|
||||||
|
|
||||||
|
nsresult rv = sUUIDGenerator->GenerateUUIDInPlace(&aUUID);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t
|
uint64_t
|
||||||
nsContentUtils::GetInnerWindowID(nsIRequest* aRequest)
|
nsContentUtils::GetInnerWindowID(nsIRequest* aRequest)
|
||||||
{
|
{
|
||||||
|
|
|
@ -85,6 +85,7 @@ class nsIStringBundleService;
|
||||||
class nsISupportsArray;
|
class nsISupportsArray;
|
||||||
class nsISupportsHashKey;
|
class nsISupportsHashKey;
|
||||||
class nsIURI;
|
class nsIURI;
|
||||||
|
class nsIUUIDGenerator;
|
||||||
class nsIWidget;
|
class nsIWidget;
|
||||||
class nsIWordBreaker;
|
class nsIWordBreaker;
|
||||||
class nsIXPConnect;
|
class nsIXPConnect;
|
||||||
|
@ -853,6 +854,11 @@ public:
|
||||||
*/
|
*/
|
||||||
static uint32_t ParseSandboxAttributeToFlags(const nsAttrValue* sandboxAttr);
|
static uint32_t ParseSandboxAttributeToFlags(const nsAttrValue* sandboxAttr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function that generates a UUID.
|
||||||
|
*/
|
||||||
|
static nsresult GenerateUUIDInPlace(nsID& aUUID);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fill (with the parameters given) the localized string named |aKey| in
|
* Fill (with the parameters given) the localized string named |aKey| in
|
||||||
|
@ -2443,6 +2449,7 @@ private:
|
||||||
static nsNameSpaceManager *sNameSpaceManager;
|
static nsNameSpaceManager *sNameSpaceManager;
|
||||||
|
|
||||||
static nsIIOService *sIOService;
|
static nsIIOService *sIOService;
|
||||||
|
static nsIUUIDGenerator *sUUIDGenerator;
|
||||||
|
|
||||||
static bool sImgLoaderInitialized;
|
static bool sImgLoaderInitialized;
|
||||||
static void InitImgLoader();
|
static void InitImgLoader();
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "nsIComponentManager.h"
|
#include "nsIComponentManager.h"
|
||||||
#include "nsIServiceManager.h"
|
#include "nsIServiceManager.h"
|
||||||
#include "nsIClipboard.h"
|
#include "nsIClipboard.h"
|
||||||
|
#include "nsIFormControl.h"
|
||||||
#include "nsISelection.h"
|
#include "nsISelection.h"
|
||||||
#include "nsWidgetsCID.h"
|
#include "nsWidgetsCID.h"
|
||||||
#include "nsXPCOM.h"
|
#include "nsXPCOM.h"
|
||||||
|
|
|
@ -277,15 +277,15 @@ BuildClonedMessageData(typename BlobTraits<Flavor>::ConcreteContentManagerType*
|
||||||
SerializedStructuredCloneBuffer& buffer = aClonedData.data();
|
SerializedStructuredCloneBuffer& buffer = aClonedData.data();
|
||||||
buffer.data = aData.mData;
|
buffer.data = aData.mData;
|
||||||
buffer.dataLength = aData.mDataLength;
|
buffer.dataLength = aData.mDataLength;
|
||||||
const nsTArray<nsRefPtr<Blob>>& blobs = aData.mClosure.mBlobs;
|
const nsTArray<nsRefPtr<BlobImpl>>& blobImpls = aData.mClosure.mBlobImpls;
|
||||||
if (!blobs.IsEmpty()) {
|
if (!blobImpls.IsEmpty()) {
|
||||||
typedef typename BlobTraits<Flavor>::ProtocolType ProtocolType;
|
typedef typename BlobTraits<Flavor>::ProtocolType ProtocolType;
|
||||||
InfallibleTArray<ProtocolType*>& blobList = DataBlobs<Flavor>::Blobs(aClonedData);
|
InfallibleTArray<ProtocolType*>& blobList = DataBlobs<Flavor>::Blobs(aClonedData);
|
||||||
uint32_t length = blobs.Length();
|
uint32_t length = blobImpls.Length();
|
||||||
blobList.SetCapacity(length);
|
blobList.SetCapacity(length);
|
||||||
for (uint32_t i = 0; i < length; ++i) {
|
for (uint32_t i = 0; i < length; ++i) {
|
||||||
typename BlobTraits<Flavor>::BlobType* protocolActor =
|
typename BlobTraits<Flavor>::BlobType* protocolActor =
|
||||||
aManager->GetOrCreateActorForBlob(blobs[i]);
|
aManager->GetOrCreateActorForBlobImpl(blobImpls[i]);
|
||||||
if (!protocolActor) {
|
if (!protocolActor) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -323,7 +323,7 @@ UnpackClonedMessageData(const ClonedMessageData& aData)
|
||||||
cloneData.mDataLength = buffer.dataLength;
|
cloneData.mDataLength = buffer.dataLength;
|
||||||
if (!blobs.IsEmpty()) {
|
if (!blobs.IsEmpty()) {
|
||||||
uint32_t length = blobs.Length();
|
uint32_t length = blobs.Length();
|
||||||
cloneData.mClosure.mBlobs.SetCapacity(length);
|
cloneData.mClosure.mBlobImpls.SetCapacity(length);
|
||||||
for (uint32_t i = 0; i < length; ++i) {
|
for (uint32_t i = 0; i < length; ++i) {
|
||||||
auto* blob =
|
auto* blob =
|
||||||
static_cast<typename BlobTraits<Flavor>::BlobType*>(blobs[i]);
|
static_cast<typename BlobTraits<Flavor>::BlobType*>(blobs[i]);
|
||||||
|
@ -332,10 +332,7 @@ UnpackClonedMessageData(const ClonedMessageData& aData)
|
||||||
nsRefPtr<BlobImpl> blobImpl = blob->GetBlobImpl();
|
nsRefPtr<BlobImpl> blobImpl = blob->GetBlobImpl();
|
||||||
MOZ_ASSERT(blobImpl);
|
MOZ_ASSERT(blobImpl);
|
||||||
|
|
||||||
// This object will be duplicated with a correct parent before being
|
cloneData.mClosure.mBlobImpls.AppendElement(blobImpl);
|
||||||
// exposed to JS.
|
|
||||||
nsRefPtr<Blob> domBlob = Blob::Create(nullptr, blobImpl);
|
|
||||||
cloneData.mClosure.mBlobs.AppendElement(domBlob);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cloneData;
|
return cloneData;
|
||||||
|
|
|
@ -59,7 +59,6 @@
|
||||||
#include "nsLayoutStatics.h"
|
#include "nsLayoutStatics.h"
|
||||||
#include "nsCCUncollectableMarker.h"
|
#include "nsCCUncollectableMarker.h"
|
||||||
#include "mozilla/dom/workers/Workers.h"
|
#include "mozilla/dom/workers/Workers.h"
|
||||||
#include "mozilla/dom/MessagePortList.h"
|
|
||||||
#include "mozilla/dom/ToJSValue.h"
|
#include "mozilla/dom/ToJSValue.h"
|
||||||
#include "nsJSPrincipals.h"
|
#include "nsJSPrincipals.h"
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
|
@ -69,9 +68,9 @@
|
||||||
#include "mozilla/MouseEvents.h"
|
#include "mozilla/MouseEvents.h"
|
||||||
#include "mozilla/ProcessHangMonitor.h"
|
#include "mozilla/ProcessHangMonitor.h"
|
||||||
#include "AudioChannelService.h"
|
#include "AudioChannelService.h"
|
||||||
#include "MessageEvent.h"
|
|
||||||
#include "nsAboutProtocolUtils.h"
|
#include "nsAboutProtocolUtils.h"
|
||||||
#include "nsCharTraits.h" // NS_IS_HIGH/LOW_SURROGATE
|
#include "nsCharTraits.h" // NS_IS_HIGH/LOW_SURROGATE
|
||||||
|
#include "PostMessageEvent.h"
|
||||||
|
|
||||||
// Interfaces Needed
|
// Interfaces Needed
|
||||||
#include "nsIFrame.h"
|
#include "nsIFrame.h"
|
||||||
|
@ -179,13 +178,9 @@
|
||||||
#include "prprf.h"
|
#include "prprf.h"
|
||||||
|
|
||||||
#include "mozilla/dom/MessageChannel.h"
|
#include "mozilla/dom/MessageChannel.h"
|
||||||
#include "mozilla/dom/MessagePort.h"
|
|
||||||
#include "mozilla/dom/MessagePortBinding.h"
|
|
||||||
#include "mozilla/dom/indexedDB/IDBFactory.h"
|
#include "mozilla/dom/indexedDB/IDBFactory.h"
|
||||||
#include "mozilla/dom/Promise.h"
|
#include "mozilla/dom/Promise.h"
|
||||||
|
|
||||||
#include "mozilla/dom/StructuredCloneTags.h"
|
|
||||||
|
|
||||||
#ifdef MOZ_GAMEPAD
|
#ifdef MOZ_GAMEPAD
|
||||||
#include "mozilla/dom/Gamepad.h"
|
#include "mozilla/dom/Gamepad.h"
|
||||||
#include "mozilla/dom/GamepadService.h"
|
#include "mozilla/dom/GamepadService.h"
|
||||||
|
@ -207,7 +202,6 @@
|
||||||
#include "TimeChangeObserver.h"
|
#include "TimeChangeObserver.h"
|
||||||
#include "TouchCaret.h"
|
#include "TouchCaret.h"
|
||||||
#include "mozilla/dom/AudioContext.h"
|
#include "mozilla/dom/AudioContext.h"
|
||||||
#include "mozilla/dom/BlobBinding.h"
|
|
||||||
#include "mozilla/dom/BrowserElementDictionariesBinding.h"
|
#include "mozilla/dom/BrowserElementDictionariesBinding.h"
|
||||||
#include "mozilla/dom/cache/CacheStorage.h"
|
#include "mozilla/dom/cache/CacheStorage.h"
|
||||||
#include "mozilla/dom/Console.h"
|
#include "mozilla/dom/Console.h"
|
||||||
|
@ -8038,367 +8032,6 @@ nsGlobalWindow::CallerInnerWindow()
|
||||||
return static_cast<nsGlobalWindow*>(win.get());
|
return static_cast<nsGlobalWindow*>(win.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Class used to represent events generated by calls to Window.postMessage,
|
|
||||||
* which asynchronously creates and dispatches events.
|
|
||||||
*/
|
|
||||||
class PostMessageEvent : public nsRunnable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
NS_DECL_NSIRUNNABLE
|
|
||||||
|
|
||||||
PostMessageEvent(nsGlobalWindow* aSource,
|
|
||||||
const nsAString& aCallerOrigin,
|
|
||||||
nsGlobalWindow* aTargetWindow,
|
|
||||||
nsIPrincipal* aProvidedPrincipal,
|
|
||||||
bool aTrustedCaller)
|
|
||||||
: mSource(aSource),
|
|
||||||
mCallerOrigin(aCallerOrigin),
|
|
||||||
mTargetWindow(aTargetWindow),
|
|
||||||
mProvidedPrincipal(aProvidedPrincipal),
|
|
||||||
mTrustedCaller(aTrustedCaller)
|
|
||||||
{
|
|
||||||
MOZ_COUNT_CTOR(PostMessageEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
~PostMessageEvent()
|
|
||||||
{
|
|
||||||
MOZ_COUNT_DTOR(PostMessageEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
JSAutoStructuredCloneBuffer& Buffer()
|
|
||||||
{
|
|
||||||
return mBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool StoreISupports(nsISupports* aSupports)
|
|
||||||
{
|
|
||||||
mSupportsArray.AppendElement(aSupports);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
JSAutoStructuredCloneBuffer mBuffer;
|
|
||||||
nsRefPtr<nsGlobalWindow> mSource;
|
|
||||||
nsString mCallerOrigin;
|
|
||||||
nsRefPtr<nsGlobalWindow> mTargetWindow;
|
|
||||||
nsCOMPtr<nsIPrincipal> mProvidedPrincipal;
|
|
||||||
bool mTrustedCaller;
|
|
||||||
nsTArray<nsCOMPtr<nsISupports> > mSupportsArray;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
struct StructuredCloneInfo {
|
|
||||||
PostMessageEvent* event;
|
|
||||||
bool subsumes;
|
|
||||||
nsPIDOMWindow* window;
|
|
||||||
nsRefPtrHashtable<nsRefPtrHashKey<MessagePortBase>, MessagePortBase> ports;
|
|
||||||
};
|
|
||||||
|
|
||||||
static JSObject*
|
|
||||||
PostMessageReadStructuredClone(JSContext* cx,
|
|
||||||
JSStructuredCloneReader* reader,
|
|
||||||
uint32_t tag,
|
|
||||||
uint32_t data,
|
|
||||||
void* closure)
|
|
||||||
{
|
|
||||||
StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure);
|
|
||||||
NS_ASSERTION(scInfo, "Must have scInfo!");
|
|
||||||
|
|
||||||
if (tag == SCTAG_DOM_BLOB) {
|
|
||||||
NS_ASSERTION(!data, "Data should be empty");
|
|
||||||
|
|
||||||
// What we get back from the reader is a BlobImpl.
|
|
||||||
// From that we create a new File.
|
|
||||||
BlobImpl* blobImpl;
|
|
||||||
if (JS_ReadBytes(reader, &blobImpl, sizeof(blobImpl))) {
|
|
||||||
MOZ_ASSERT(blobImpl);
|
|
||||||
|
|
||||||
// nsRefPtr<File> needs to go out of scope before toObjectOrNull() is
|
|
||||||
// called because the static analysis thinks dereferencing XPCOM objects
|
|
||||||
// can GC (because in some cases it can!), and a return statement with a
|
|
||||||
// JSObject* type means that JSObject* is on the stack as a raw pointer
|
|
||||||
// while destructors are running.
|
|
||||||
JS::Rooted<JS::Value> val(cx);
|
|
||||||
{
|
|
||||||
nsRefPtr<Blob> blob = Blob::Create(scInfo->window, blobImpl);
|
|
||||||
if (!ToJSValue(cx, blob, &val)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &val.toObject();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tag == SCTAG_DOM_FILELIST) {
|
|
||||||
NS_ASSERTION(!data, "Data should be empty");
|
|
||||||
|
|
||||||
nsISupports* supports;
|
|
||||||
if (JS_ReadBytes(reader, &supports, sizeof(supports))) {
|
|
||||||
JS::Rooted<JS::Value> val(cx);
|
|
||||||
if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, supports, &val))) {
|
|
||||||
return val.toObjectOrNull();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const JSStructuredCloneCallbacks* runtimeCallbacks =
|
|
||||||
js::GetContextStructuredCloneCallbacks(cx);
|
|
||||||
|
|
||||||
if (runtimeCallbacks) {
|
|
||||||
return runtimeCallbacks->read(cx, reader, tag, data, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
PostMessageWriteStructuredClone(JSContext* cx,
|
|
||||||
JSStructuredCloneWriter* writer,
|
|
||||||
JS::Handle<JSObject*> obj,
|
|
||||||
void *closure)
|
|
||||||
{
|
|
||||||
StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure);
|
|
||||||
NS_ASSERTION(scInfo, "Must have scInfo!");
|
|
||||||
|
|
||||||
// See if this is a File/Blob object.
|
|
||||||
{
|
|
||||||
Blob* blob = nullptr;
|
|
||||||
if (scInfo->subsumes && NS_SUCCEEDED(UNWRAP_OBJECT(Blob, obj, blob))) {
|
|
||||||
BlobImpl* blobImpl = blob->Impl();
|
|
||||||
if (JS_WriteUint32Pair(writer, SCTAG_DOM_BLOB, 0) &&
|
|
||||||
JS_WriteBytes(writer, &blobImpl, sizeof(blobImpl))) {
|
|
||||||
scInfo->event->StoreISupports(blobImpl);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative;
|
|
||||||
nsContentUtils::XPConnect()->
|
|
||||||
GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wrappedNative));
|
|
||||||
if (wrappedNative) {
|
|
||||||
uint32_t scTag = 0;
|
|
||||||
nsISupports* supports = wrappedNative->Native();
|
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMFileList> list = do_QueryInterface(supports);
|
|
||||||
if (list && scInfo->subsumes)
|
|
||||||
scTag = SCTAG_DOM_FILELIST;
|
|
||||||
|
|
||||||
if (scTag)
|
|
||||||
return JS_WriteUint32Pair(writer, scTag, 0) &&
|
|
||||||
JS_WriteBytes(writer, &supports, sizeof(supports)) &&
|
|
||||||
scInfo->event->StoreISupports(supports);
|
|
||||||
}
|
|
||||||
|
|
||||||
const JSStructuredCloneCallbacks* runtimeCallbacks =
|
|
||||||
js::GetContextStructuredCloneCallbacks(cx);
|
|
||||||
|
|
||||||
if (runtimeCallbacks) {
|
|
||||||
return runtimeCallbacks->write(cx, writer, obj, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
PostMessageReadTransferStructuredClone(JSContext* aCx,
|
|
||||||
JSStructuredCloneReader* reader,
|
|
||||||
uint32_t tag, void* aData,
|
|
||||||
uint64_t aExtraData,
|
|
||||||
void* aClosure,
|
|
||||||
JS::MutableHandle<JSObject*> returnObject)
|
|
||||||
{
|
|
||||||
StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(aClosure);
|
|
||||||
NS_ASSERTION(scInfo, "Must have scInfo!");
|
|
||||||
|
|
||||||
if (tag == SCTAG_DOM_MAP_MESSAGEPORT) {
|
|
||||||
MessagePort* port = static_cast<MessagePort*>(aData);
|
|
||||||
port->BindToOwner(scInfo->window);
|
|
||||||
scInfo->ports.Put(port, nullptr);
|
|
||||||
|
|
||||||
JS::Rooted<JSObject*> obj(aCx, port->WrapObject(aCx, nullptr));
|
|
||||||
if (JS_WrapObject(aCx, &obj)) {
|
|
||||||
MOZ_ASSERT(port->GetOwner() == scInfo->window);
|
|
||||||
returnObject.set(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
PostMessageTransferStructuredClone(JSContext* aCx,
|
|
||||||
JS::Handle<JSObject*> aObj,
|
|
||||||
void* aClosure,
|
|
||||||
uint32_t* aTag,
|
|
||||||
JS::TransferableOwnership* aOwnership,
|
|
||||||
void** aContent,
|
|
||||||
uint64_t* aExtraData)
|
|
||||||
{
|
|
||||||
StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(aClosure);
|
|
||||||
NS_ASSERTION(scInfo, "Must have scInfo!");
|
|
||||||
|
|
||||||
MessagePortBase* port = nullptr;
|
|
||||||
nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port);
|
|
||||||
if (NS_SUCCEEDED(rv)) {
|
|
||||||
nsRefPtr<MessagePortBase> newPort;
|
|
||||||
if (scInfo->ports.Get(port, getter_AddRefs(newPort))) {
|
|
||||||
// No duplicate.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
newPort = port->Clone();
|
|
||||||
scInfo->ports.Put(port, newPort);
|
|
||||||
|
|
||||||
*aTag = SCTAG_DOM_MAP_MESSAGEPORT;
|
|
||||||
*aOwnership = JS::SCTAG_TMO_CUSTOM;
|
|
||||||
*aContent = newPort;
|
|
||||||
*aExtraData = 0;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
PostMessageFreeTransferStructuredClone(uint32_t aTag, JS::TransferableOwnership aOwnership,
|
|
||||||
void *aContent, uint64_t aExtraData, void* aClosure)
|
|
||||||
{
|
|
||||||
StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(aClosure);
|
|
||||||
NS_ASSERTION(scInfo, "Must have scInfo!");
|
|
||||||
|
|
||||||
if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) {
|
|
||||||
nsRefPtr<MessagePortBase> port(static_cast<MessagePort*>(aContent));
|
|
||||||
scInfo->ports.Remove(port);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const JSStructuredCloneCallbacks kPostMessageCallbacks = {
|
|
||||||
PostMessageReadStructuredClone,
|
|
||||||
PostMessageWriteStructuredClone,
|
|
||||||
nullptr,
|
|
||||||
PostMessageReadTransferStructuredClone,
|
|
||||||
PostMessageTransferStructuredClone,
|
|
||||||
PostMessageFreeTransferStructuredClone
|
|
||||||
};
|
|
||||||
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
static PLDHashOperator
|
|
||||||
PopulateMessagePortList(MessagePortBase* aKey, MessagePortBase* aValue, void* aClosure)
|
|
||||||
{
|
|
||||||
nsTArray<nsRefPtr<MessagePortBase> > *array =
|
|
||||||
static_cast<nsTArray<nsRefPtr<MessagePortBase> > *>(aClosure);
|
|
||||||
|
|
||||||
array->AppendElement(aKey);
|
|
||||||
return PL_DHASH_NEXT;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
PostMessageEvent::Run()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(mTargetWindow->IsOuterWindow(),
|
|
||||||
"should have been passed an outer window!");
|
|
||||||
MOZ_ASSERT(!mSource || mSource->IsOuterWindow(),
|
|
||||||
"should have been passed an outer window!");
|
|
||||||
|
|
||||||
AutoJSAPI jsapi;
|
|
||||||
jsapi.Init();
|
|
||||||
JSContext* cx = jsapi.cx();
|
|
||||||
|
|
||||||
// If we bailed before this point we're going to leak mMessage, but
|
|
||||||
// that's probably better than crashing.
|
|
||||||
|
|
||||||
nsRefPtr<nsGlobalWindow> targetWindow;
|
|
||||||
if (mTargetWindow->IsClosedOrClosing() ||
|
|
||||||
!(targetWindow = mTargetWindow->GetCurrentInnerWindowInternal()) ||
|
|
||||||
targetWindow->IsClosedOrClosing())
|
|
||||||
return NS_OK;
|
|
||||||
|
|
||||||
MOZ_ASSERT(targetWindow->IsInnerWindow(),
|
|
||||||
"we ordered an inner window!");
|
|
||||||
JSAutoCompartment ac(cx, targetWindow->GetWrapperPreserveColor());
|
|
||||||
|
|
||||||
// Ensure that any origin which might have been provided is the origin of this
|
|
||||||
// window's document. Note that we do this *now* instead of when postMessage
|
|
||||||
// is called because the target window might have been navigated to a
|
|
||||||
// different location between then and now. If this check happened when
|
|
||||||
// postMessage was called, it would be fairly easy for a malicious webpage to
|
|
||||||
// intercept messages intended for another site by carefully timing navigation
|
|
||||||
// of the target window so it changed location after postMessage but before
|
|
||||||
// now.
|
|
||||||
if (mProvidedPrincipal) {
|
|
||||||
// Get the target's origin either from its principal or, in the case the
|
|
||||||
// principal doesn't carry a URI (e.g. the system principal), the target's
|
|
||||||
// document.
|
|
||||||
nsIPrincipal* targetPrin = targetWindow->GetPrincipal();
|
|
||||||
if (NS_WARN_IF(!targetPrin))
|
|
||||||
return NS_OK;
|
|
||||||
|
|
||||||
// Note: This is contrary to the spec with respect to file: URLs, which
|
|
||||||
// the spec groups into a single origin, but given we intentionally
|
|
||||||
// don't do that in other places it seems better to hold the line for
|
|
||||||
// now. Long-term, we want HTML5 to address this so that we can
|
|
||||||
// be compliant while being safer.
|
|
||||||
if (!targetPrin->Equals(mProvidedPrincipal)) {
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deserialize the structured clone data
|
|
||||||
JS::Rooted<JS::Value> messageData(cx);
|
|
||||||
StructuredCloneInfo scInfo;
|
|
||||||
scInfo.event = this;
|
|
||||||
scInfo.window = targetWindow;
|
|
||||||
|
|
||||||
if (!mBuffer.read(cx, &messageData, &kPostMessageCallbacks, &scInfo)) {
|
|
||||||
return NS_ERROR_DOM_DATA_CLONE_ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the event
|
|
||||||
nsCOMPtr<mozilla::dom::EventTarget> eventTarget =
|
|
||||||
do_QueryInterface(static_cast<nsPIDOMWindow*>(targetWindow.get()));
|
|
||||||
nsRefPtr<MessageEvent> event =
|
|
||||||
new MessageEvent(eventTarget, nullptr, nullptr);
|
|
||||||
|
|
||||||
event->InitMessageEvent(NS_LITERAL_STRING("message"), false /*non-bubbling */,
|
|
||||||
false /*cancelable */, messageData, mCallerOrigin,
|
|
||||||
EmptyString(), mSource);
|
|
||||||
|
|
||||||
nsTArray<nsRefPtr<MessagePortBase> > ports;
|
|
||||||
scInfo.ports.EnumerateRead(PopulateMessagePortList, &ports);
|
|
||||||
event->SetPorts(new MessagePortList(static_cast<dom::Event*>(event.get()), ports));
|
|
||||||
|
|
||||||
// We can't simply call dispatchEvent on the window because doing so ends
|
|
||||||
// up flipping the trusted bit on the event, and we don't want that to
|
|
||||||
// happen because then untrusted content can call postMessage on a chrome
|
|
||||||
// window if it can get a reference to it.
|
|
||||||
|
|
||||||
nsIPresShell *shell = targetWindow->mDoc->GetShell();
|
|
||||||
nsRefPtr<nsPresContext> presContext;
|
|
||||||
if (shell)
|
|
||||||
presContext = shell->GetPresContext();
|
|
||||||
|
|
||||||
event->SetTrusted(mTrustedCaller);
|
|
||||||
WidgetEvent* internalEvent = event->GetInternalNSEvent();
|
|
||||||
|
|
||||||
nsEventStatus status = nsEventStatus_eIgnore;
|
|
||||||
EventDispatcher::Dispatch(static_cast<nsPIDOMWindow*>(mTargetWindow),
|
|
||||||
presContext,
|
|
||||||
internalEvent,
|
|
||||||
static_cast<dom::Event*>(event.get()),
|
|
||||||
&status);
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
nsGlobalWindow::PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
nsGlobalWindow::PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||||
const nsAString& aTargetOrigin,
|
const nsAString& aTargetOrigin,
|
||||||
|
@ -8522,18 +8155,13 @@ nsGlobalWindow::PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||||
providedPrincipal,
|
providedPrincipal,
|
||||||
nsContentUtils::IsCallerChrome());
|
nsContentUtils::IsCallerChrome());
|
||||||
|
|
||||||
// We *must* clone the data here, or the JS::Value could be modified
|
|
||||||
// by script
|
|
||||||
StructuredCloneInfo scInfo;
|
|
||||||
scInfo.event = event;
|
|
||||||
scInfo.window = this;
|
|
||||||
|
|
||||||
nsIPrincipal* principal = GetPrincipal();
|
nsIPrincipal* principal = GetPrincipal();
|
||||||
JS::Rooted<JS::Value> message(aCx, aMessage);
|
JS::Rooted<JS::Value> message(aCx, aMessage);
|
||||||
JS::Rooted<JS::Value> transfer(aCx, aTransfer);
|
JS::Rooted<JS::Value> transfer(aCx, aTransfer);
|
||||||
if (NS_FAILED(callerPrin->Subsumes(principal, &scInfo.subsumes)) ||
|
bool subsumes;
|
||||||
!event->Buffer().write(aCx, message, transfer, &kPostMessageCallbacks,
|
|
||||||
&scInfo)) {
|
if (NS_FAILED(callerPrin->Subsumes(principal, &subsumes)) ||
|
||||||
|
!event->Write(aCx, message, transfer, subsumes, this)) {
|
||||||
aError.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
|
aError.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,6 +111,7 @@ class MozSelfSupport;
|
||||||
class Navigator;
|
class Navigator;
|
||||||
class OwningExternalOrWindowProxy;
|
class OwningExternalOrWindowProxy;
|
||||||
class Promise;
|
class Promise;
|
||||||
|
class PostMessageEvent;
|
||||||
struct RequestInit;
|
struct RequestInit;
|
||||||
class RequestOrUSVString;
|
class RequestOrUSVString;
|
||||||
class Selection;
|
class Selection;
|
||||||
|
@ -1752,7 +1753,7 @@ protected:
|
||||||
|
|
||||||
friend class nsDOMScriptableHelper;
|
friend class nsDOMScriptableHelper;
|
||||||
friend class nsDOMWindowUtils;
|
friend class nsDOMWindowUtils;
|
||||||
friend class PostMessageEvent;
|
friend class mozilla::dom::PostMessageEvent;
|
||||||
friend class DesktopNotification;
|
friend class DesktopNotification;
|
||||||
|
|
||||||
static WindowByIdTable* sWindowsById;
|
static WindowByIdTable* sWindowsById;
|
||||||
|
|
|
@ -13,7 +13,6 @@ support-files =
|
||||||
[test_domrequesthelper.xul]
|
[test_domrequesthelper.xul]
|
||||||
[test_url.xul]
|
[test_url.xul]
|
||||||
[test_console.xul]
|
[test_console.xul]
|
||||||
[test_messageChannel.xul]
|
|
||||||
[test_navigator_resolve_identity_xrays.xul]
|
[test_navigator_resolve_identity_xrays.xul]
|
||||||
[test_sendQueryContentAndSelectionSetEvent.html]
|
[test_sendQueryContentAndSelectionSetEvent.html]
|
||||||
[test_bug1016960.html]
|
[test_bug1016960.html]
|
||||||
|
|
|
@ -4,10 +4,6 @@ support-files =
|
||||||
iframe_bug976673.html
|
iframe_bug976673.html
|
||||||
iframe_main_bug1022229.html
|
iframe_main_bug1022229.html
|
||||||
iframe_sandbox_bug1022229.html
|
iframe_sandbox_bug1022229.html
|
||||||
iframe_messageChannel_cloning.html
|
|
||||||
iframe_messageChannel_chrome.html
|
|
||||||
iframe_messageChannel_pingpong.html
|
|
||||||
iframe_messageChannel_post.html
|
|
||||||
file_empty.html
|
file_empty.html
|
||||||
iframe_postMessage_solidus.html
|
iframe_postMessage_solidus.html
|
||||||
file_setname.html
|
file_setname.html
|
||||||
|
@ -285,15 +281,7 @@ skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e1
|
||||||
[test_history_state_null.html]
|
[test_history_state_null.html]
|
||||||
[test_Image_constructor.html]
|
[test_Image_constructor.html]
|
||||||
[test_innersize_scrollport.html]
|
[test_innersize_scrollport.html]
|
||||||
[test_messageChannel.html]
|
|
||||||
[test_messageChannel_cloning.html]
|
|
||||||
[test_messageChannel_pingpong.html]
|
|
||||||
[test_messageChannel_post.html]
|
|
||||||
[test_messageChannel_pref.html]
|
|
||||||
[test_messageChannel_start.html]
|
|
||||||
[test_messagemanager_targetchain.html]
|
[test_messagemanager_targetchain.html]
|
||||||
[test_messageChannel_transferable.html]
|
|
||||||
[test_messageChannel_unshipped.html]
|
|
||||||
[test_named_frames.html]
|
[test_named_frames.html]
|
||||||
[test_navigator_resolve_identity.html]
|
[test_navigator_resolve_identity.html]
|
||||||
[test_navigator_language.html]
|
[test_navigator_language.html]
|
||||||
|
|
|
@ -729,9 +729,6 @@ DOMInterfaces = {
|
||||||
'MessagePort': {
|
'MessagePort': {
|
||||||
'nativeType': 'mozilla::dom::MessagePortBase',
|
'nativeType': 'mozilla::dom::MessagePortBase',
|
||||||
'headerFile': 'mozilla/dom/MessagePort.h',
|
'headerFile': 'mozilla/dom/MessagePort.h',
|
||||||
'binaryNames': {
|
|
||||||
'postMessage': 'postMessageMoz',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
|
||||||
'MimeType': {
|
'MimeType': {
|
||||||
|
|
|
@ -212,14 +212,15 @@ public:
|
||||||
PBackgroundChild* backgroundManager = mActor->Manager();
|
PBackgroundChild* backgroundManager = mActor->Manager();
|
||||||
MOZ_ASSERT(backgroundManager);
|
MOZ_ASSERT(backgroundManager);
|
||||||
|
|
||||||
const nsTArray<nsRefPtr<Blob>>& blobs = mData->mClosure.mBlobs;
|
const nsTArray<nsRefPtr<BlobImpl>>& blobImpls = mData->mClosure.mBlobImpls;
|
||||||
|
|
||||||
if (!blobs.IsEmpty()) {
|
if (!blobImpls.IsEmpty()) {
|
||||||
message.blobsChild().SetCapacity(blobs.Length());
|
message.blobsChild().SetCapacity(blobImpls.Length());
|
||||||
|
|
||||||
for (uint32_t i = 0, len = blobs.Length(); i < len; ++i) {
|
for (uint32_t i = 0, len = blobImpls.Length(); i < len; ++i) {
|
||||||
PBlobChild* blobChild =
|
PBlobChild* blobChild =
|
||||||
BackgroundChild::GetOrCreateActorForBlob(backgroundManager, blobs[i]);
|
BackgroundChild::GetOrCreateActorForBlobImpl(backgroundManager,
|
||||||
|
blobImpls[i]);
|
||||||
MOZ_ASSERT(blobChild);
|
MOZ_ASSERT(blobChild);
|
||||||
|
|
||||||
message.blobsChild().AppendElement(blobChild);
|
message.blobsChild().AppendElement(blobChild);
|
||||||
|
@ -541,9 +542,9 @@ BroadcastChannel::PostMessageInternal(JSContext* aCx,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const nsTArray<nsRefPtr<Blob>>& blobs = data->mClosure.mBlobs;
|
const nsTArray<nsRefPtr<BlobImpl>>& blobImpls = data->mClosure.mBlobImpls;
|
||||||
for (uint32_t i = 0, len = blobs.Length(); i < len; ++i) {
|
for (uint32_t i = 0, len = blobImpls.Length(); i < len; ++i) {
|
||||||
if (!blobs[i]->Impl()->MayBeClonedToOtherThreads()) {
|
if (!blobImpls[i]->MayBeClonedToOtherThreads()) {
|
||||||
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
|
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ BroadcastChannelChild::RecvNotify(const ClonedMessageData& aData)
|
||||||
{
|
{
|
||||||
// Make sure to retrieve all blobs from the message before returning to avoid
|
// Make sure to retrieve all blobs from the message before returning to avoid
|
||||||
// leaking their actors.
|
// leaking their actors.
|
||||||
nsTArray<nsRefPtr<Blob>> blobs;
|
nsTArray<nsRefPtr<BlobImpl>> blobs;
|
||||||
if (!aData.blobsChild().IsEmpty()) {
|
if (!aData.blobsChild().IsEmpty()) {
|
||||||
blobs.SetCapacity(aData.blobsChild().Length());
|
blobs.SetCapacity(aData.blobsChild().Length());
|
||||||
|
|
||||||
|
@ -50,8 +50,7 @@ BroadcastChannelChild::RecvNotify(const ClonedMessageData& aData)
|
||||||
nsRefPtr<BlobImpl> impl =
|
nsRefPtr<BlobImpl> impl =
|
||||||
static_cast<BlobChild*>(aData.blobsChild()[i])->GetBlobImpl();
|
static_cast<BlobChild*>(aData.blobsChild()[i])->GetBlobImpl();
|
||||||
|
|
||||||
nsRefPtr<Blob> blob = Blob::Create(mBC ? mBC->GetOwner() : nullptr, impl);
|
blobs.AppendElement(impl);
|
||||||
blobs.AppendElement(blob);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,7 +91,7 @@ BroadcastChannelChild::RecvNotify(const ClonedMessageData& aData)
|
||||||
StructuredCloneData cloneData;
|
StructuredCloneData cloneData;
|
||||||
cloneData.mData = buffer.data;
|
cloneData.mData = buffer.data;
|
||||||
cloneData.mDataLength = buffer.dataLength;
|
cloneData.mDataLength = buffer.dataLength;
|
||||||
cloneData.mClosure.mBlobs.SwapElements(blobs);
|
cloneData.mClosure.mBlobImpls.SwapElements(blobs);
|
||||||
|
|
||||||
JS::Rooted<JS::Value> value(cx, JS::NullValue());
|
JS::Rooted<JS::Value> value(cx, JS::NullValue());
|
||||||
if (cloneData.mDataLength && !ReadStructuredClone(cx, cloneData, &value)) {
|
if (cloneData.mDataLength && !ReadStructuredClone(cx, cloneData, &value)) {
|
||||||
|
|
|
@ -50,14 +50,14 @@ Read(JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag,
|
||||||
// while destructors are running.
|
// while destructors are running.
|
||||||
JS::Rooted<JS::Value> val(aCx);
|
JS::Rooted<JS::Value> val(aCx);
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aData < closure->mBlobs.Length());
|
MOZ_ASSERT(aData < closure->mBlobImpls.Length());
|
||||||
nsRefPtr<Blob> blob = closure->mBlobs[aData];
|
nsRefPtr<BlobImpl> blobImpl = closure->mBlobImpls[aData];
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
{
|
{
|
||||||
// Blob should not be mutable.
|
// Blob should not be mutable.
|
||||||
bool isMutable;
|
bool isMutable;
|
||||||
MOZ_ASSERT(NS_SUCCEEDED(blob->GetMutable(&isMutable)));
|
MOZ_ASSERT(NS_SUCCEEDED(blobImpl->GetMutable(&isMutable)));
|
||||||
MOZ_ASSERT(!isMutable);
|
MOZ_ASSERT(!isMutable);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -66,7 +66,7 @@ Read(JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag,
|
||||||
nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
|
nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
|
||||||
MOZ_ASSERT(global);
|
MOZ_ASSERT(global);
|
||||||
|
|
||||||
nsRefPtr<Blob> newBlob = Blob::Create(global, blob->Impl());
|
nsRefPtr<Blob> newBlob = Blob::Create(global, blobImpl);
|
||||||
if (!ToJSValue(aCx, newBlob, &val)) {
|
if (!ToJSValue(aCx, newBlob, &val)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -93,8 +93,8 @@ Write(JSContext* aCx, JSStructuredCloneWriter* aWriter,
|
||||||
if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob)) &&
|
if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob)) &&
|
||||||
NS_SUCCEEDED(blob->SetMutable(false)) &&
|
NS_SUCCEEDED(blob->SetMutable(false)) &&
|
||||||
JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB,
|
JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB,
|
||||||
closure->mBlobs.Length())) {
|
closure->mBlobImpls.Length())) {
|
||||||
closure->mBlobs.AppendElement(blob);
|
closure->mBlobImpls.AppendElement(blob->Impl());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace dom {
|
||||||
struct
|
struct
|
||||||
StructuredCloneClosure
|
StructuredCloneClosure
|
||||||
{
|
{
|
||||||
nsTArray<nsRefPtr<Blob>> mBlobs;
|
nsTArray<nsRefPtr<BlobImpl>> mBlobImpls;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct
|
struct
|
||||||
|
|
|
@ -0,0 +1,228 @@
|
||||||
|
/* -*- 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 "MessageChannel.h"
|
||||||
|
|
||||||
|
#include "mozilla/Preferences.h"
|
||||||
|
#include "mozilla/dom/MessageChannelBinding.h"
|
||||||
|
#include "mozilla/dom/MessagePort.h"
|
||||||
|
#include "mozilla/dom/Navigator.h"
|
||||||
|
#include "mozilla/dom/WorkerPrivate.h"
|
||||||
|
#include "mozilla/dom/WorkerRunnable.h"
|
||||||
|
#include "nsContentUtils.h"
|
||||||
|
#include "nsIDocument.h"
|
||||||
|
#include "nsIPrincipal.h"
|
||||||
|
#include "nsPIDOMWindow.h"
|
||||||
|
#include "nsServiceManagerUtils.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MessageChannel, mWindow, mPort1, mPort2)
|
||||||
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(MessageChannel)
|
||||||
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(MessageChannel)
|
||||||
|
|
||||||
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MessageChannel)
|
||||||
|
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||||
|
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||||
|
NS_INTERFACE_MAP_END
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
bool gPrefInitialized = false;
|
||||||
|
bool gPrefEnabled = false;
|
||||||
|
|
||||||
|
bool
|
||||||
|
CheckPermission(nsIPrincipal* aPrincipal, bool aCallerChrome)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
if (!gPrefInitialized) {
|
||||||
|
Preferences::AddBoolVarCache(&gPrefEnabled, "dom.messageChannel.enabled");
|
||||||
|
gPrefInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enabled by pref
|
||||||
|
if (gPrefEnabled) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chrome callers are allowed.
|
||||||
|
if (aCallerChrome) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIURI> uri;
|
||||||
|
if (NS_FAILED(aPrincipal->GetURI(getter_AddRefs(uri))) || !uri) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isResource = false;
|
||||||
|
if (NS_FAILED(uri->SchemeIs("resource", &isResource))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsIPrincipal*
|
||||||
|
GetPrincipalFromWorkerPrivate(workers::WorkerPrivate* aWorkerPrivate)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
nsIPrincipal* principal = aWorkerPrivate->GetPrincipal();
|
||||||
|
if (principal) {
|
||||||
|
return principal;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walk up to our containing page
|
||||||
|
workers::WorkerPrivate* wp = aWorkerPrivate;
|
||||||
|
while (wp->GetParent()) {
|
||||||
|
wp = wp->GetParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
nsPIDOMWindow* window = wp->GetWindow();
|
||||||
|
if (!window) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsIDocument* doc = window->GetExtantDoc();
|
||||||
|
if (!doc) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return doc->NodePrincipal();
|
||||||
|
}
|
||||||
|
|
||||||
|
// A WorkerMainThreadRunnable to synchronously dispatch the call of
|
||||||
|
// CheckPermission() from the worker thread to the main thread.
|
||||||
|
class CheckPermissionRunnable final : public workers::WorkerMainThreadRunnable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool mResult;
|
||||||
|
bool mCallerChrome;
|
||||||
|
|
||||||
|
explicit CheckPermissionRunnable(workers::WorkerPrivate* aWorkerPrivate)
|
||||||
|
: workers::WorkerMainThreadRunnable(aWorkerPrivate)
|
||||||
|
, mResult(false)
|
||||||
|
, mCallerChrome(false)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aWorkerPrivate);
|
||||||
|
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||||
|
mCallerChrome = aWorkerPrivate->UsesSystemPrincipal();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual bool
|
||||||
|
MainThreadRun() override
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
nsIPrincipal* principal = GetPrincipalFromWorkerPrivate(mWorkerPrivate);
|
||||||
|
if (!principal) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isNullPrincipal;
|
||||||
|
nsresult rv = principal->GetIsNullPrincipal(&isNullPrincipal);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NS_WARN_IF(isNullPrincipal)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
mResult = CheckPermission(principal, mCallerChrome);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
/* static */ bool
|
||||||
|
MessageChannel::Enabled(JSContext* aCx, JSObject* aGlobal)
|
||||||
|
{
|
||||||
|
if (NS_IsMainThread()) {
|
||||||
|
JS::Rooted<JSObject*> global(aCx, aGlobal);
|
||||||
|
|
||||||
|
nsCOMPtr<nsPIDOMWindow> win = Navigator::GetWindowFromGlobal(global);
|
||||||
|
if (!win) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsIDocument* doc = win->GetExtantDoc();
|
||||||
|
if (!doc) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CheckPermission(doc->NodePrincipal(),
|
||||||
|
nsContentUtils::IsCallerChrome());
|
||||||
|
}
|
||||||
|
|
||||||
|
workers::WorkerPrivate* workerPrivate =
|
||||||
|
workers::GetWorkerPrivateFromContext(aCx);
|
||||||
|
workerPrivate->AssertIsOnWorkerThread();
|
||||||
|
|
||||||
|
nsRefPtr<CheckPermissionRunnable> runnable =
|
||||||
|
new CheckPermissionRunnable(workerPrivate);
|
||||||
|
runnable->Dispatch(aCx);
|
||||||
|
|
||||||
|
return runnable->mResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageChannel::MessageChannel(nsPIDOMWindow* aWindow)
|
||||||
|
: mWindow(aWindow)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageChannel::~MessageChannel()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
JSObject*
|
||||||
|
MessageChannel::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||||
|
{
|
||||||
|
return MessageChannelBinding::Wrap(aCx, this, aGivenProto);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */ already_AddRefed<MessageChannel>
|
||||||
|
MessageChannel::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
|
||||||
|
{
|
||||||
|
// window can be null in workers.
|
||||||
|
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
|
||||||
|
|
||||||
|
nsID portUUID1;
|
||||||
|
aRv = nsContentUtils::GenerateUUIDInPlace(portUUID1);
|
||||||
|
if (aRv.Failed()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsID portUUID2;
|
||||||
|
aRv = nsContentUtils::GenerateUUIDInPlace(portUUID2);
|
||||||
|
if (aRv.Failed()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsRefPtr<MessageChannel> channel = new MessageChannel(window);
|
||||||
|
|
||||||
|
channel->mPort1 = MessagePort::Create(window, portUUID1, portUUID2, aRv);
|
||||||
|
if (NS_WARN_IF(aRv.Failed())) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
channel->mPort2 = MessagePort::Create(window, portUUID2, portUUID1, aRv);
|
||||||
|
if (NS_WARN_IF(aRv.Failed())) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
channel->mPort1->UnshippedEntangle(channel->mPort2);
|
||||||
|
channel->mPort2->UnshippedEntangle(channel->mPort1);
|
||||||
|
|
||||||
|
return channel.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace dom
|
||||||
|
} // namespace mozilla
|
|
@ -31,8 +31,6 @@ public:
|
||||||
static bool Enabled(JSContext* aCx, JSObject* aGlobal);
|
static bool Enabled(JSContext* aCx, JSObject* aGlobal);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit MessageChannel(nsPIDOMWindow* aWindow);
|
|
||||||
|
|
||||||
nsPIDOMWindow*
|
nsPIDOMWindow*
|
||||||
GetParentObject() const
|
GetParentObject() const
|
||||||
{
|
{
|
||||||
|
@ -58,6 +56,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
explicit MessageChannel(nsPIDOMWindow* aWindow);
|
||||||
~MessageChannel();
|
~MessageChannel();
|
||||||
|
|
||||||
nsCOMPtr<nsPIDOMWindow> mWindow;
|
nsCOMPtr<nsPIDOMWindow> mWindow;
|
|
@ -0,0 +1,867 @@
|
||||||
|
/* -*- 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 "MessagePort.h"
|
||||||
|
|
||||||
|
#include "MessageEvent.h"
|
||||||
|
#include "MessagePortChild.h"
|
||||||
|
#include "mozilla/dom/BlobBinding.h"
|
||||||
|
#include "mozilla/dom/Event.h"
|
||||||
|
#include "mozilla/dom/File.h"
|
||||||
|
#include "mozilla/dom/MessageChannel.h"
|
||||||
|
#include "mozilla/dom/MessagePortBinding.h"
|
||||||
|
#include "mozilla/dom/MessagePortChild.h"
|
||||||
|
#include "mozilla/dom/MessagePortList.h"
|
||||||
|
#include "mozilla/dom/PMessagePort.h"
|
||||||
|
#include "mozilla/dom/StructuredCloneTags.h"
|
||||||
|
#include "mozilla/dom/WorkerPrivate.h"
|
||||||
|
#include "mozilla/dom/WorkerScope.h"
|
||||||
|
#include "mozilla/ipc/BackgroundChild.h"
|
||||||
|
#include "mozilla/ipc/PBackgroundChild.h"
|
||||||
|
#include "nsContentUtils.h"
|
||||||
|
#include "nsGlobalWindow.h"
|
||||||
|
#include "nsPresContext.h"
|
||||||
|
#include "ScriptSettings.h"
|
||||||
|
#include "SharedMessagePortMessage.h"
|
||||||
|
|
||||||
|
#include "nsIBFCacheEntry.h"
|
||||||
|
#include "nsIDocument.h"
|
||||||
|
#include "nsIDOMFileList.h"
|
||||||
|
#include "nsIPresShell.h"
|
||||||
|
#include "nsISupportsPrimitives.h"
|
||||||
|
#include "nsServiceManagerUtils.h"
|
||||||
|
|
||||||
|
#ifdef XP_WIN
|
||||||
|
#undef PostMessage
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace mozilla::dom::workers;
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
class DispatchEventRunnable final : public nsICancelableRunnable
|
||||||
|
{
|
||||||
|
friend class MessagePort;
|
||||||
|
|
||||||
|
public:
|
||||||
|
NS_DECL_ISUPPORTS
|
||||||
|
|
||||||
|
explicit DispatchEventRunnable(MessagePort* aPort)
|
||||||
|
: mPort(aPort)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
NS_IMETHOD
|
||||||
|
Run() override
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mPort);
|
||||||
|
MOZ_ASSERT(mPort->mDispatchRunnable == this);
|
||||||
|
mPort->mDispatchRunnable = nullptr;
|
||||||
|
mPort->Dispatch();
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHOD
|
||||||
|
Cancel() override
|
||||||
|
{
|
||||||
|
mPort = nullptr;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
~DispatchEventRunnable()
|
||||||
|
{}
|
||||||
|
|
||||||
|
nsRefPtr<MessagePort> mPort;
|
||||||
|
};
|
||||||
|
|
||||||
|
NS_IMPL_ISUPPORTS(DispatchEventRunnable, nsICancelableRunnable, nsIRunnable)
|
||||||
|
|
||||||
|
class PostMessageRunnable final : public nsICancelableRunnable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NS_DECL_ISUPPORTS
|
||||||
|
|
||||||
|
PostMessageRunnable(MessagePort* aPort, SharedMessagePortMessage* aData)
|
||||||
|
: mPort(aPort)
|
||||||
|
, mData(aData)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aPort);
|
||||||
|
MOZ_ASSERT(aData);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHOD
|
||||||
|
Run() override
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIGlobalObject> globalObject;
|
||||||
|
|
||||||
|
if (NS_IsMainThread()) {
|
||||||
|
globalObject = do_QueryInterface(mPort->GetParentObject());
|
||||||
|
} else {
|
||||||
|
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
|
||||||
|
MOZ_ASSERT(workerPrivate);
|
||||||
|
globalObject = workerPrivate->GlobalScope();
|
||||||
|
}
|
||||||
|
|
||||||
|
AutoJSAPI jsapi;
|
||||||
|
if (!globalObject || !jsapi.Init(globalObject)) {
|
||||||
|
NS_WARNING("Failed to initialize AutoJSAPI object.");
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSContext* cx = jsapi.cx();
|
||||||
|
|
||||||
|
nsTArray<nsRefPtr<MessagePort>> ports;
|
||||||
|
nsCOMPtr<nsPIDOMWindow> window =
|
||||||
|
do_QueryInterface(mPort->GetParentObject());
|
||||||
|
|
||||||
|
JS::Rooted<JS::Value> value(cx);
|
||||||
|
if (!mData->mData.IsEmpty()) {
|
||||||
|
bool ok = ReadStructuredCloneWithTransfer(cx, mData->mData,
|
||||||
|
mData->mClosure,
|
||||||
|
&value, window, ports);
|
||||||
|
FreeStructuredClone(mData->mData, mData->mClosure);
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The data should be already be cleaned.
|
||||||
|
MOZ_ASSERT(!mData->mData.Length());
|
||||||
|
|
||||||
|
// Create the event
|
||||||
|
nsCOMPtr<mozilla::dom::EventTarget> eventTarget =
|
||||||
|
do_QueryInterface(mPort->GetOwner());
|
||||||
|
nsRefPtr<MessageEvent> event =
|
||||||
|
new MessageEvent(eventTarget, nullptr, nullptr);
|
||||||
|
|
||||||
|
event->InitMessageEvent(NS_LITERAL_STRING("message"),
|
||||||
|
false /* non-bubbling */,
|
||||||
|
false /* cancelable */, value, EmptyString(),
|
||||||
|
EmptyString(), nullptr);
|
||||||
|
event->SetTrusted(true);
|
||||||
|
event->SetSource(mPort);
|
||||||
|
|
||||||
|
nsTArray<nsRefPtr<MessagePortBase>> array;
|
||||||
|
array.SetCapacity(ports.Length());
|
||||||
|
for (uint32_t i = 0; i < ports.Length(); ++i) {
|
||||||
|
array.AppendElement(ports[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsRefPtr<MessagePortList> portList =
|
||||||
|
new MessagePortList(static_cast<dom::Event*>(event.get()), array);
|
||||||
|
event->SetPorts(portList);
|
||||||
|
|
||||||
|
bool dummy;
|
||||||
|
mPort->DispatchEvent(static_cast<dom::Event*>(event.get()), &dummy);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHOD
|
||||||
|
Cancel() override
|
||||||
|
{
|
||||||
|
mPort = nullptr;
|
||||||
|
mData = nullptr;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
~PostMessageRunnable()
|
||||||
|
{}
|
||||||
|
|
||||||
|
nsRefPtr<MessagePort> mPort;
|
||||||
|
nsRefPtr<SharedMessagePortMessage> mData;
|
||||||
|
};
|
||||||
|
|
||||||
|
NS_IMPL_ISUPPORTS(PostMessageRunnable, nsICancelableRunnable, nsIRunnable)
|
||||||
|
|
||||||
|
MessagePortBase::MessagePortBase(nsPIDOMWindow* aWindow)
|
||||||
|
: DOMEventTargetHelper(aWindow)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MessagePortBase::MessagePortBase()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_CLASS(MessagePort)
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MessagePort,
|
||||||
|
MessagePortBase)
|
||||||
|
if (tmp->mDispatchRunnable) {
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDispatchRunnable->mPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessages);
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessagesForTheOtherPort);
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mUnshippedEntangledPort);
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MessagePort,
|
||||||
|
MessagePortBase)
|
||||||
|
if (tmp->mDispatchRunnable) {
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDispatchRunnable->mPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUnshippedEntangledPort);
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||||
|
|
||||||
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MessagePort)
|
||||||
|
NS_INTERFACE_MAP_ENTRY(nsIIPCBackgroundChildCreateCallback)
|
||||||
|
NS_INTERFACE_MAP_ENTRY(nsIObserver)
|
||||||
|
NS_INTERFACE_MAP_END_INHERITING(MessagePortBase)
|
||||||
|
|
||||||
|
NS_IMPL_ADDREF_INHERITED(MessagePort, MessagePortBase)
|
||||||
|
NS_IMPL_RELEASE_INHERITED(MessagePort, MessagePortBase)
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class MessagePortFeature final : public workers::WorkerFeature
|
||||||
|
{
|
||||||
|
MessagePort* mPort;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit MessagePortFeature(MessagePort* aPort)
|
||||||
|
: mPort(aPort)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aPort);
|
||||||
|
MOZ_COUNT_CTOR(MessagePortFeature);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool Notify(JSContext* aCx, workers::Status aStatus) override
|
||||||
|
{
|
||||||
|
if (mPort && aStatus > Running) {
|
||||||
|
mPort->Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
~MessagePortFeature()
|
||||||
|
{
|
||||||
|
MOZ_COUNT_DTOR(MessagePortFeature);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
MessagePort::MessagePort(nsPIDOMWindow* aWindow)
|
||||||
|
: MessagePortBase(aWindow)
|
||||||
|
, mInnerID(0)
|
||||||
|
, mMessageQueueEnabled(false)
|
||||||
|
, mIsKeptAlive(false)
|
||||||
|
{
|
||||||
|
mIdentifier = new MessagePortIdentifier();
|
||||||
|
mIdentifier->neutered() = true;
|
||||||
|
mIdentifier->sequenceId() = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
MessagePort::~MessagePort()
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
MOZ_ASSERT(!mWorkerFeature);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */ already_AddRefed<MessagePort>
|
||||||
|
MessagePort::Create(nsPIDOMWindow* aWindow, const nsID& aUUID,
|
||||||
|
const nsID& aDestinationUUID, ErrorResult& aRv)
|
||||||
|
{
|
||||||
|
nsRefPtr<MessagePort> mp = new MessagePort(aWindow);
|
||||||
|
mp->Initialize(aUUID, aDestinationUUID, 1 /* 0 is an invalid sequence ID */,
|
||||||
|
false /* Neutered */, eStateUnshippedEntangled, aRv);
|
||||||
|
return mp.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */ already_AddRefed<MessagePort>
|
||||||
|
MessagePort::Create(nsPIDOMWindow* aWindow,
|
||||||
|
const MessagePortIdentifier& aIdentifier,
|
||||||
|
ErrorResult& aRv)
|
||||||
|
{
|
||||||
|
nsRefPtr<MessagePort> mp = new MessagePort(aWindow);
|
||||||
|
mp->Initialize(aIdentifier.uuid(), aIdentifier.destinationUuid(),
|
||||||
|
aIdentifier.sequenceId(), aIdentifier.neutered(),
|
||||||
|
eStateEntangling, aRv);
|
||||||
|
return mp.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MessagePort::UnshippedEntangle(MessagePort* aEntangledPort)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aEntangledPort);
|
||||||
|
MOZ_ASSERT(!mUnshippedEntangledPort);
|
||||||
|
|
||||||
|
mUnshippedEntangledPort = aEntangledPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MessagePort::Initialize(const nsID& aUUID,
|
||||||
|
const nsID& aDestinationUUID,
|
||||||
|
uint32_t aSequenceID, bool mNeutered,
|
||||||
|
State aState, ErrorResult& aRv)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mIdentifier);
|
||||||
|
mIdentifier->uuid() = aUUID;
|
||||||
|
mIdentifier->destinationUuid() = aDestinationUUID;
|
||||||
|
mIdentifier->sequenceId() = aSequenceID;
|
||||||
|
|
||||||
|
mState = aState;
|
||||||
|
mNextStep = eNextStepNone;
|
||||||
|
|
||||||
|
if (mNeutered) {
|
||||||
|
mState = eStateDisentangled;
|
||||||
|
} else if (mState == eStateEntangling) {
|
||||||
|
ConnectToPBackground();
|
||||||
|
} else {
|
||||||
|
MOZ_ASSERT(mState == eStateUnshippedEntangled);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The port has to keep itself alive until it's entangled.
|
||||||
|
UpdateMustKeepAlive();
|
||||||
|
|
||||||
|
if (NS_IsMainThread()) {
|
||||||
|
MOZ_ASSERT(GetOwner());
|
||||||
|
MOZ_ASSERT(GetOwner()->IsInnerWindow());
|
||||||
|
mInnerID = GetOwner()->WindowID();
|
||||||
|
|
||||||
|
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||||
|
if (obs) {
|
||||||
|
obs->AddObserver(this, "inner-window-destroyed", false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
|
||||||
|
MOZ_ASSERT(workerPrivate);
|
||||||
|
MOZ_ASSERT(!mWorkerFeature);
|
||||||
|
|
||||||
|
nsAutoPtr<WorkerFeature> feature(new MessagePortFeature(this));
|
||||||
|
JSContext* cx = workerPrivate->GetJSContext();
|
||||||
|
if (NS_WARN_IF(!workerPrivate->AddFeature(cx, feature))) {
|
||||||
|
aRv.Throw(NS_ERROR_FAILURE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mWorkerFeature = Move(feature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JSObject*
|
||||||
|
MessagePort::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||||
|
{
|
||||||
|
return MessagePortBinding::Wrap(aCx, this, aGivenProto);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MessagePort::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||||
|
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||||
|
ErrorResult& aRv)
|
||||||
|
{
|
||||||
|
// We *must* clone the data here, or the JS::Value could be modified
|
||||||
|
// by script
|
||||||
|
|
||||||
|
JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue());
|
||||||
|
if (aTransferable.WasPassed()) {
|
||||||
|
const Sequence<JS::Value>& realTransferable = aTransferable.Value();
|
||||||
|
|
||||||
|
// Here we want to check if the transerable object list contains
|
||||||
|
// this port. No other checks are done.
|
||||||
|
for (const JS::Value& value : realTransferable) {
|
||||||
|
if (!value.isObject()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
MessagePortBase* port = nullptr;
|
||||||
|
nsresult rv = UNWRAP_OBJECT(MessagePort, &value.toObject(), port);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (port == this) {
|
||||||
|
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The input sequence only comes from the generated bindings code, which
|
||||||
|
// ensures it is rooted.
|
||||||
|
JS::HandleValueArray elements =
|
||||||
|
JS::HandleValueArray::fromMarkedLocation(realTransferable.Length(),
|
||||||
|
realTransferable.Elements());
|
||||||
|
|
||||||
|
JSObject* array =
|
||||||
|
JS_NewArrayObject(aCx, elements);
|
||||||
|
if (!array) {
|
||||||
|
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
transferable.setObject(*array);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsRefPtr<SharedMessagePortMessage> data = new SharedMessagePortMessage();
|
||||||
|
|
||||||
|
if (!WriteStructuredCloneWithTransfer(aCx, aMessage, transferable,
|
||||||
|
data->mData, data->mClosure)) {
|
||||||
|
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This message has to be ignored.
|
||||||
|
if (mState > eStateEntangled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are unshipped we are connected to the other port on the same thread.
|
||||||
|
if (mState == eStateUnshippedEntangled) {
|
||||||
|
MOZ_ASSERT(mUnshippedEntangledPort);
|
||||||
|
mUnshippedEntangledPort->mMessages.AppendElement(data);
|
||||||
|
mUnshippedEntangledPort->Dispatch();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not entangled yet, but already closed.
|
||||||
|
if (mNextStep != eNextStepNone) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoveDocFromBFCache();
|
||||||
|
|
||||||
|
// Not entangled yet.
|
||||||
|
if (mState == eStateEntangling) {
|
||||||
|
mMessagesForTheOtherPort.AppendElement(data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(mActor);
|
||||||
|
MOZ_ASSERT(mMessagesForTheOtherPort.IsEmpty());
|
||||||
|
|
||||||
|
nsAutoTArray<nsRefPtr<SharedMessagePortMessage>, 1> array;
|
||||||
|
array.AppendElement(data);
|
||||||
|
|
||||||
|
nsAutoTArray<MessagePortMessage, 1> messages;
|
||||||
|
SharedMessagePortMessage::FromSharedToMessagesChild(mActor, array, messages);
|
||||||
|
mActor->SendPostMessages(messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MessagePort::Start()
|
||||||
|
{
|
||||||
|
if (mMessageQueueEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mMessageQueueEnabled = true;
|
||||||
|
Dispatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MessagePort::Dispatch()
|
||||||
|
{
|
||||||
|
if (!mMessageQueueEnabled || mMessages.IsEmpty() || mDispatchRunnable ||
|
||||||
|
mState > eStateEntangled || mNextStep != eNextStepNone) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsRefPtr<SharedMessagePortMessage> data = mMessages.ElementAt(0);
|
||||||
|
mMessages.RemoveElementAt(0);
|
||||||
|
|
||||||
|
nsRefPtr<PostMessageRunnable> runnable = new PostMessageRunnable(this, data);
|
||||||
|
|
||||||
|
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToCurrentThread(runnable)));
|
||||||
|
|
||||||
|
mDispatchRunnable = new DispatchEventRunnable(this);
|
||||||
|
|
||||||
|
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToCurrentThread(mDispatchRunnable)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MessagePort::Close()
|
||||||
|
{
|
||||||
|
// Not entangled yet, but already closed.
|
||||||
|
if (mNextStep != eNextStepNone) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mState == eStateUnshippedEntangled) {
|
||||||
|
MOZ_ASSERT(mUnshippedEntangledPort);
|
||||||
|
|
||||||
|
// This avoids loops.
|
||||||
|
nsRefPtr<MessagePort> port = Move(mUnshippedEntangledPort);
|
||||||
|
MOZ_ASSERT(mUnshippedEntangledPort == nullptr);
|
||||||
|
|
||||||
|
mState = eStateDisentangled;
|
||||||
|
port->Close();
|
||||||
|
|
||||||
|
UpdateMustKeepAlive();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not entangled yet, we have to wait.
|
||||||
|
if (mState < eStateEntangling) {
|
||||||
|
mNextStep = eNextStepClose;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mState > eStateEntangled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't care about stopping the sending of messages because from now all
|
||||||
|
// the incoming messages will be ignored.
|
||||||
|
mState = eStateDisentangled;
|
||||||
|
|
||||||
|
MOZ_ASSERT(mActor);
|
||||||
|
|
||||||
|
mActor->SendClose();
|
||||||
|
mActor->SetPort(nullptr);
|
||||||
|
mActor = nullptr;
|
||||||
|
|
||||||
|
UpdateMustKeepAlive();
|
||||||
|
}
|
||||||
|
|
||||||
|
EventHandlerNonNull*
|
||||||
|
MessagePort::GetOnmessage()
|
||||||
|
{
|
||||||
|
if (NS_IsMainThread()) {
|
||||||
|
return GetEventHandler(nsGkAtoms::onmessage, EmptyString());
|
||||||
|
}
|
||||||
|
return GetEventHandler(nullptr, NS_LITERAL_STRING("message"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MessagePort::SetOnmessage(EventHandlerNonNull* aCallback)
|
||||||
|
{
|
||||||
|
if (NS_IsMainThread()) {
|
||||||
|
SetEventHandler(nsGkAtoms::onmessage, EmptyString(), aCallback);
|
||||||
|
} else {
|
||||||
|
SetEventHandler(nullptr, NS_LITERAL_STRING("message"), aCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
// When using onmessage, the call to start() is implied.
|
||||||
|
Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method is called when the PMessagePortChild actor is entangled to
|
||||||
|
// another actor. It receives a list of messages to be dispatch. It can be that
|
||||||
|
// we were waiting for this entangling step in order to disentangle the port or
|
||||||
|
// to close it.
|
||||||
|
void
|
||||||
|
MessagePort::Entangled(nsTArray<MessagePortMessage>& aMessages)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mState == eStateEntangling);
|
||||||
|
|
||||||
|
mState = eStateEntangled;
|
||||||
|
|
||||||
|
// If we have pending messages, these have to be sent.
|
||||||
|
if (!mMessagesForTheOtherPort.IsEmpty()) {
|
||||||
|
nsTArray<MessagePortMessage> messages;
|
||||||
|
SharedMessagePortMessage::FromSharedToMessagesChild(mActor,
|
||||||
|
mMessagesForTheOtherPort,
|
||||||
|
messages);
|
||||||
|
mMessagesForTheOtherPort.Clear();
|
||||||
|
mActor->SendPostMessages(messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We must convert the messages into SharedMessagePortMessages to avoid leaks.
|
||||||
|
FallibleTArray<nsRefPtr<SharedMessagePortMessage>> data;
|
||||||
|
if (NS_WARN_IF(!SharedMessagePortMessage::FromMessagesToSharedChild(aMessages,
|
||||||
|
data))) {
|
||||||
|
// OOM, we cannot continue.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mNextStep == eNextStepClose) {
|
||||||
|
Close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mMessages.AppendElements(data);
|
||||||
|
|
||||||
|
// We were waiting for the entangling callback in order to disentangle this
|
||||||
|
// port immediately after.
|
||||||
|
if (mNextStep == eNextStepDisentangle) {
|
||||||
|
StartDisentangling();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(mNextStep == eNextStepNone);
|
||||||
|
Dispatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MessagePort::StartDisentangling()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mActor);
|
||||||
|
MOZ_ASSERT(mState == eStateEntangled);
|
||||||
|
|
||||||
|
mState = eStateDisentangling;
|
||||||
|
mNextStep = eNextStepNone;
|
||||||
|
|
||||||
|
// Sending this message we communicate to the parent actor that we don't want
|
||||||
|
// to receive any new messages. It is possible that a message has been
|
||||||
|
// already sent but not received yet. So we have to collect all of them and
|
||||||
|
// we send them in the SendDispatch() request.
|
||||||
|
mActor->SendStopSendingData();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MessagePort::MessagesReceived(nsTArray<MessagePortMessage>& aMessages)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mState == eStateEntangled || mState == eStateDisentangling);
|
||||||
|
MOZ_ASSERT(mNextStep == eNextStepNone);
|
||||||
|
MOZ_ASSERT(mMessagesForTheOtherPort.IsEmpty());
|
||||||
|
|
||||||
|
RemoveDocFromBFCache();
|
||||||
|
|
||||||
|
FallibleTArray<nsRefPtr<SharedMessagePortMessage>> data;
|
||||||
|
if (!NS_WARN_IF(SharedMessagePortMessage::FromMessagesToSharedChild(aMessages,
|
||||||
|
data))) {
|
||||||
|
// OOM, We cannot continue.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mMessages.AppendElements(data);
|
||||||
|
|
||||||
|
if (mState == eStateEntangled) {
|
||||||
|
Dispatch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MessagePort::StopSendingDataConfirmed()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mState == eStateDisentangling);
|
||||||
|
MOZ_ASSERT(mActor);
|
||||||
|
|
||||||
|
Disentangle();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MessagePort::Disentangle()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mState == eStateDisentangling);
|
||||||
|
MOZ_ASSERT(mActor);
|
||||||
|
|
||||||
|
mState = eStateDisentangled;
|
||||||
|
|
||||||
|
nsTArray<MessagePortMessage> messages;
|
||||||
|
SharedMessagePortMessage::FromSharedToMessagesChild(mActor, mMessages,
|
||||||
|
messages);
|
||||||
|
mMessages.Clear();
|
||||||
|
mActor->SendDisentangle(messages);
|
||||||
|
|
||||||
|
mActor->SetPort(nullptr);
|
||||||
|
mActor = nullptr;
|
||||||
|
|
||||||
|
UpdateMustKeepAlive();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MessagePort::CloneAndDisentangle(MessagePortIdentifier& aIdentifier)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mIdentifier);
|
||||||
|
|
||||||
|
// We can clone a port that has already been transfered. In this case, on the
|
||||||
|
// otherside will have a neutered port. Here we set neutered to true so that
|
||||||
|
// we are safe in case a early return.
|
||||||
|
aIdentifier.neutered() = true;
|
||||||
|
|
||||||
|
if (mState > eStateEntangled) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We already have a 'next step'. We have to consider this port as already
|
||||||
|
// cloned/closed/disentangled.
|
||||||
|
if (mNextStep != eNextStepNone) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
aIdentifier.uuid() = mIdentifier->uuid();
|
||||||
|
aIdentifier.destinationUuid() = mIdentifier->destinationUuid();
|
||||||
|
aIdentifier.sequenceId() = mIdentifier->sequenceId() + 1;
|
||||||
|
aIdentifier.neutered() = false;
|
||||||
|
|
||||||
|
// We have to entangle first.
|
||||||
|
if (mState == eStateUnshippedEntangled) {
|
||||||
|
MOZ_ASSERT(mUnshippedEntangledPort);
|
||||||
|
MOZ_ASSERT(mMessagesForTheOtherPort.IsEmpty());
|
||||||
|
|
||||||
|
// Disconnect the entangled port and connect it to PBackground.
|
||||||
|
mUnshippedEntangledPort->ConnectToPBackground();
|
||||||
|
mUnshippedEntangledPort = nullptr;
|
||||||
|
|
||||||
|
// In this case, we don't need to be connected to the PBackground service.
|
||||||
|
if (mMessages.IsEmpty()) {
|
||||||
|
aIdentifier.sequenceId() = mIdentifier->sequenceId();
|
||||||
|
|
||||||
|
mState = eStateDisentangled;
|
||||||
|
UpdateMustKeepAlive();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register this component to PBackground.
|
||||||
|
ConnectToPBackground();
|
||||||
|
|
||||||
|
mNextStep = eNextStepDisentangle;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not entangled yet, we have to wait.
|
||||||
|
if (mState < eStateEntangled) {
|
||||||
|
mNextStep = eNextStepDisentangle;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
StartDisentangling();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MessagePort::Closed()
|
||||||
|
{
|
||||||
|
if (mState == eStateDisentangled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mState = eStateDisentangled;
|
||||||
|
|
||||||
|
if (mActor) {
|
||||||
|
mActor->SetPort(nullptr);
|
||||||
|
mActor = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateMustKeepAlive();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MessagePort::ConnectToPBackground()
|
||||||
|
{
|
||||||
|
mState = eStateEntangling;
|
||||||
|
|
||||||
|
PBackgroundChild* actor =
|
||||||
|
mozilla::ipc::BackgroundChild::GetForCurrentThread();
|
||||||
|
if (actor) {
|
||||||
|
ActorCreated(actor);
|
||||||
|
} else {
|
||||||
|
if (NS_WARN_IF(
|
||||||
|
!mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread(this))) {
|
||||||
|
MOZ_CRASH();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MessagePort::ActorFailed()
|
||||||
|
{
|
||||||
|
MOZ_CRASH("Failed to create a PBackgroundChild actor!");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MessagePort::ActorCreated(mozilla::ipc::PBackgroundChild* aActor)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aActor);
|
||||||
|
MOZ_ASSERT(!mActor);
|
||||||
|
MOZ_ASSERT(mIdentifier);
|
||||||
|
MOZ_ASSERT(mState == eStateEntangling);
|
||||||
|
|
||||||
|
PMessagePortChild* actor =
|
||||||
|
aActor->SendPMessagePortConstructor(mIdentifier->uuid(),
|
||||||
|
mIdentifier->destinationUuid(),
|
||||||
|
mIdentifier->sequenceId());
|
||||||
|
|
||||||
|
mActor = static_cast<MessagePortChild*>(actor);
|
||||||
|
MOZ_ASSERT(mActor);
|
||||||
|
|
||||||
|
mActor->SetPort(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MessagePort::UpdateMustKeepAlive()
|
||||||
|
{
|
||||||
|
if (mState == eStateDisentangled && mIsKeptAlive) {
|
||||||
|
mIsKeptAlive = false;
|
||||||
|
|
||||||
|
if (mWorkerFeature) {
|
||||||
|
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
|
||||||
|
MOZ_ASSERT(workerPrivate);
|
||||||
|
|
||||||
|
workerPrivate->RemoveFeature(workerPrivate->GetJSContext(),
|
||||||
|
mWorkerFeature);
|
||||||
|
mWorkerFeature = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Release();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mState < eStateDisentangled && !mIsKeptAlive) {
|
||||||
|
mIsKeptAlive = true;
|
||||||
|
AddRef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
MessagePort::Observe(nsISupports* aSubject, const char* aTopic,
|
||||||
|
const char16_t* aData)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
if (strcmp(aTopic, "inner-window-destroyed")) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the window id destroyed we have to release the reference that we are
|
||||||
|
// keeping.
|
||||||
|
if (!mIsKeptAlive) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsISupportsPRUint64> 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<nsIObserverService> obs =
|
||||||
|
do_GetService("@mozilla.org/observer-service;1");
|
||||||
|
if (obs) {
|
||||||
|
obs->RemoveObserver(this, "inner-window-destroyed");
|
||||||
|
}
|
||||||
|
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MessagePort::RemoveDocFromBFCache()
|
||||||
|
{
|
||||||
|
if (!NS_IsMainThread()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsPIDOMWindow* window = GetOwner();
|
||||||
|
MOZ_ASSERT(window);
|
||||||
|
|
||||||
|
nsIDocument* doc = window->GetExtantDoc();
|
||||||
|
if (!doc) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIBFCacheEntry> bfCacheEntry = doc->GetBFCacheEntry();
|
||||||
|
if (!bfCacheEntry) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bfCacheEntry->RemoveFromBFCacheSync();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace dom
|
||||||
|
} // namespace mozilla
|
|
@ -0,0 +1,210 @@
|
||||||
|
/* -*- 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_MessagePort_h
|
||||||
|
#define mozilla_dom_MessagePort_h
|
||||||
|
|
||||||
|
#include "mozilla/Attributes.h"
|
||||||
|
#include "mozilla/DOMEventTargetHelper.h"
|
||||||
|
#include "nsIIPCBackgroundChildCreateCallback.h"
|
||||||
|
#include "nsTArray.h"
|
||||||
|
|
||||||
|
#ifdef XP_WIN
|
||||||
|
#undef PostMessage
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class nsPIDOMWindow;
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
class DispatchEventRunnable;
|
||||||
|
class MessagePortChild;
|
||||||
|
class MessagePortIdentifier;
|
||||||
|
class MessagePortMessage;
|
||||||
|
class SharedMessagePortMessage;
|
||||||
|
|
||||||
|
namespace workers {
|
||||||
|
class WorkerFeature;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MessagePortBase : public DOMEventTargetHelper
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
explicit MessagePortBase(nsPIDOMWindow* aWindow);
|
||||||
|
MessagePortBase();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void
|
||||||
|
PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||||
|
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||||
|
ErrorResult& aRv) = 0;
|
||||||
|
|
||||||
|
virtual void
|
||||||
|
Start() = 0;
|
||||||
|
|
||||||
|
virtual void
|
||||||
|
Close() = 0;
|
||||||
|
|
||||||
|
// The 'message' event handler has to call |Start()| method, so we
|
||||||
|
// cannot use IMPL_EVENT_HANDLER macro here.
|
||||||
|
virtual EventHandlerNonNull*
|
||||||
|
GetOnmessage() = 0;
|
||||||
|
|
||||||
|
virtual void
|
||||||
|
SetOnmessage(EventHandlerNonNull* aCallback) = 0;
|
||||||
|
|
||||||
|
// Duplicate this message port. This method is used by the Structured Clone
|
||||||
|
// Algorithm and populates a MessagePortIdentifier object with the information
|
||||||
|
// useful to create new MessagePort.
|
||||||
|
virtual bool
|
||||||
|
CloneAndDisentangle(MessagePortIdentifier& aIdentifier) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MessagePort final : public MessagePortBase
|
||||||
|
, public nsIIPCBackgroundChildCreateCallback
|
||||||
|
, public nsIObserver
|
||||||
|
{
|
||||||
|
friend class DispatchEventRunnable;
|
||||||
|
|
||||||
|
public:
|
||||||
|
NS_DECL_NSIIPCBACKGROUNDCHILDCREATECALLBACK
|
||||||
|
NS_DECL_NSIOBSERVER
|
||||||
|
NS_DECL_ISUPPORTS_INHERITED
|
||||||
|
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MessagePort,
|
||||||
|
DOMEventTargetHelper)
|
||||||
|
|
||||||
|
static already_AddRefed<MessagePort>
|
||||||
|
Create(nsPIDOMWindow* aWindow, const nsID& aUUID,
|
||||||
|
const nsID& aDestinationUUID, ErrorResult& aRv);
|
||||||
|
|
||||||
|
static already_AddRefed<MessagePort>
|
||||||
|
Create(nsPIDOMWindow* aWindow, const MessagePortIdentifier& aIdentifier,
|
||||||
|
ErrorResult& aRv);
|
||||||
|
|
||||||
|
virtual JSObject*
|
||||||
|
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||||
|
|
||||||
|
virtual void
|
||||||
|
PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||||
|
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||||
|
ErrorResult& aRv) override;
|
||||||
|
|
||||||
|
virtual void Start() override;
|
||||||
|
|
||||||
|
virtual void Close() override;
|
||||||
|
|
||||||
|
virtual EventHandlerNonNull* GetOnmessage() override;
|
||||||
|
|
||||||
|
virtual void SetOnmessage(EventHandlerNonNull* aCallback) override;
|
||||||
|
|
||||||
|
// Non WebIDL methods
|
||||||
|
|
||||||
|
void UnshippedEntangle(MessagePort* aEntangledPort);
|
||||||
|
|
||||||
|
virtual bool CloneAndDisentangle(MessagePortIdentifier& aIdentifier) override;
|
||||||
|
|
||||||
|
// These methods are useful for MessagePortChild
|
||||||
|
|
||||||
|
void Entangled(nsTArray<MessagePortMessage>& aMessages);
|
||||||
|
void MessagesReceived(nsTArray<MessagePortMessage>& aMessages);
|
||||||
|
void StopSendingDataConfirmed();
|
||||||
|
void Closed();
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit MessagePort(nsPIDOMWindow* aWindow);
|
||||||
|
~MessagePort();
|
||||||
|
|
||||||
|
enum State {
|
||||||
|
// When a port is created by a MessageChannel it is entangled with the
|
||||||
|
// other. They both run on the same thread, same event loop and the
|
||||||
|
// messages are added to the queues without using PBackground actors.
|
||||||
|
// When one of the port is shipped, the state is changed to
|
||||||
|
// StateEntangling.
|
||||||
|
eStateUnshippedEntangled,
|
||||||
|
|
||||||
|
// If the port is closed or cloned when we are in this state, we set the
|
||||||
|
// mNextStep. This 'next' operation will be done when entangled() message
|
||||||
|
// is received.
|
||||||
|
eStateEntangling,
|
||||||
|
|
||||||
|
// When entangled() is received we send all the messages in the
|
||||||
|
// mMessagesForTheOtherPort to the actor and we change the state to
|
||||||
|
// StateEntangled. At this point the port is entangled with the other. We
|
||||||
|
// send and receive messages.
|
||||||
|
// If the port queue is not enabled, the received messages are stored in
|
||||||
|
// the mMessages.
|
||||||
|
eStateEntangled,
|
||||||
|
|
||||||
|
// When the port is cloned or disentangled we want to stop receiving
|
||||||
|
// messages. We call 'SendStopSendingData' to the actor and we wait for an
|
||||||
|
// answer. All the messages received between now and the
|
||||||
|
// 'StopSendingDataComfirmed are queued in the mMessages but not
|
||||||
|
// dispatched.
|
||||||
|
eStateDisentangling,
|
||||||
|
|
||||||
|
// When 'StopSendingDataConfirmed' is received, we can disentangle the port
|
||||||
|
// calling SendDisentangle in the actor because we are 100% sure that we
|
||||||
|
// don't receive any other message, so nothing will be lost.
|
||||||
|
// Disentangling the port we send all the messages from the mMessages
|
||||||
|
// though the actor.
|
||||||
|
eStateDisentangled
|
||||||
|
};
|
||||||
|
|
||||||
|
void Initialize(const nsID& aUUID, const nsID& aDestinationUUID,
|
||||||
|
uint32_t aSequenceID, bool mNeutered, State aState,
|
||||||
|
ErrorResult& aRv);
|
||||||
|
|
||||||
|
void ConnectToPBackground();
|
||||||
|
|
||||||
|
// Dispatch events from the Message Queue using a nsRunnable.
|
||||||
|
void Dispatch();
|
||||||
|
|
||||||
|
void StartDisentangling();
|
||||||
|
void Disentangle();
|
||||||
|
|
||||||
|
void RemoveDocFromBFCache();
|
||||||
|
|
||||||
|
// This method is meant to keep alive the MessagePort when this object is
|
||||||
|
// creating the actor and until the actor is entangled.
|
||||||
|
// We release the object when the port is closed or disentangled.
|
||||||
|
void UpdateMustKeepAlive();
|
||||||
|
|
||||||
|
nsAutoPtr<workers::WorkerFeature> mWorkerFeature;
|
||||||
|
|
||||||
|
nsRefPtr<DispatchEventRunnable> mDispatchRunnable;
|
||||||
|
|
||||||
|
nsRefPtr<MessagePortChild> mActor;
|
||||||
|
|
||||||
|
nsRefPtr<MessagePort> mUnshippedEntangledPort;
|
||||||
|
|
||||||
|
nsTArray<nsRefPtr<SharedMessagePortMessage>> mMessages;
|
||||||
|
nsTArray<nsRefPtr<SharedMessagePortMessage>> mMessagesForTheOtherPort;
|
||||||
|
|
||||||
|
nsAutoPtr<MessagePortIdentifier> mIdentifier;
|
||||||
|
|
||||||
|
uint64_t mInnerID;
|
||||||
|
|
||||||
|
State mState;
|
||||||
|
|
||||||
|
// This 'nextStep' is used when we are waiting to be entangled but the
|
||||||
|
// content has called Clone() or Close().
|
||||||
|
enum {
|
||||||
|
eNextStepNone,
|
||||||
|
eNextStepDisentangle,
|
||||||
|
eNextStepClose
|
||||||
|
} mNextStep;
|
||||||
|
|
||||||
|
bool mMessageQueueEnabled;
|
||||||
|
|
||||||
|
bool mIsKeptAlive;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace dom
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif // mozilla_dom_MessagePort_h
|
|
@ -0,0 +1,49 @@
|
||||||
|
/* -*- Mode: C++; 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/. */
|
||||||
|
|
||||||
|
#include "MessagePortChild.h"
|
||||||
|
#include "MessagePort.h"
|
||||||
|
#include "mozilla/dom/MessageEvent.h"
|
||||||
|
#include "mozilla/ipc/PBackgroundChild.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
bool
|
||||||
|
MessagePortChild::RecvStopSendingDataConfirmed()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mPort);
|
||||||
|
mPort->StopSendingDataConfirmed();
|
||||||
|
MOZ_ASSERT(!mPort);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MessagePortChild::RecvEntangled(nsTArray<MessagePortMessage>&& aMessages)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mPort);
|
||||||
|
mPort->Entangled(aMessages);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MessagePortChild::RecvReceiveData(nsTArray<MessagePortMessage>&& aMessages)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mPort);
|
||||||
|
mPort->MessagesReceived(aMessages);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MessagePortChild::ActorDestroy(ActorDestroyReason aWhy)
|
||||||
|
{
|
||||||
|
if (mPort) {
|
||||||
|
mPort->Closed();
|
||||||
|
MOZ_ASSERT(!mPort);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // dom namespace
|
||||||
|
} // mozilla namespace
|
|
@ -0,0 +1,52 @@
|
||||||
|
/* 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_MessagePortChild_h
|
||||||
|
#define mozilla_dom_MessagePortChild_h
|
||||||
|
|
||||||
|
#include "mozilla/Assertions.h"
|
||||||
|
#include "mozilla/dom/PMessagePortChild.h"
|
||||||
|
#include "nsISupportsImpl.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
class MessagePort;
|
||||||
|
|
||||||
|
class MessagePortChild final : public PMessagePortChild
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NS_INLINE_DECL_REFCOUNTING(MessagePortChild)
|
||||||
|
|
||||||
|
MessagePortChild() {}
|
||||||
|
|
||||||
|
void SetPort(MessagePort* aPort)
|
||||||
|
{
|
||||||
|
mPort = aPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
~MessagePortChild()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(!mPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool
|
||||||
|
RecvEntangled(nsTArray<MessagePortMessage>&& aMessages) override;
|
||||||
|
|
||||||
|
virtual bool
|
||||||
|
RecvReceiveData(nsTArray<MessagePortMessage>&& aMessages) override;
|
||||||
|
|
||||||
|
virtual bool RecvStopSendingDataConfirmed() override;
|
||||||
|
|
||||||
|
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||||
|
|
||||||
|
// This is a raw pointer because this child is owned by this MessagePort.
|
||||||
|
MessagePort* mPort;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // dom namespace
|
||||||
|
} // mozilla namespace
|
||||||
|
|
||||||
|
#endif // mozilla_dom_MessagePortChild_h
|
|
@ -0,0 +1,163 @@
|
||||||
|
/* -*- Mode: C++; 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/. */
|
||||||
|
|
||||||
|
#include "MessagePortParent.h"
|
||||||
|
#include "MessagePortService.h"
|
||||||
|
#include "SharedMessagePortMessage.h"
|
||||||
|
#include "mozilla/unused.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
MessagePortParent::MessagePortParent(const nsID& aUUID)
|
||||||
|
: mService(MessagePortService::GetOrCreate())
|
||||||
|
, mUUID(aUUID)
|
||||||
|
, mEntangled(false)
|
||||||
|
, mCanSendData(true)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mService);
|
||||||
|
}
|
||||||
|
|
||||||
|
MessagePortParent::~MessagePortParent()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(!mService);
|
||||||
|
MOZ_ASSERT(!mEntangled);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MessagePortParent::Entangle(const nsID& aDestinationUUID,
|
||||||
|
const uint32_t& aSequenceID)
|
||||||
|
{
|
||||||
|
if (!mService) {
|
||||||
|
NS_WARNING("Entangle is called after a shutdown!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(!mEntangled);
|
||||||
|
|
||||||
|
return mService->RequestEntangling(this, aDestinationUUID, aSequenceID);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MessagePortParent::RecvPostMessages(nsTArray<MessagePortMessage>&& aMessages)
|
||||||
|
{
|
||||||
|
// This converts the object in a data struct where we have BlobImpls.
|
||||||
|
FallibleTArray<nsRefPtr<SharedMessagePortMessage>> messages;
|
||||||
|
if (NS_WARN_IF(
|
||||||
|
!SharedMessagePortMessage::FromMessagesToSharedParent(aMessages,
|
||||||
|
messages))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mEntangled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mService) {
|
||||||
|
NS_WARNING("Entangle is called after a shutdown!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (messages.IsEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mService->PostMessages(this, messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MessagePortParent::RecvDisentangle(nsTArray<MessagePortMessage>&& aMessages)
|
||||||
|
{
|
||||||
|
// This converts the object in a data struct where we have BlobImpls.
|
||||||
|
FallibleTArray<nsRefPtr<SharedMessagePortMessage>> messages;
|
||||||
|
if (NS_WARN_IF(
|
||||||
|
!SharedMessagePortMessage::FromMessagesToSharedParent(aMessages,
|
||||||
|
messages))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mEntangled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mService) {
|
||||||
|
NS_WARNING("Entangle is called after a shutdown!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mService->DisentanglePort(this, messages)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseAndDelete();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MessagePortParent::RecvStopSendingData()
|
||||||
|
{
|
||||||
|
if (!mEntangled) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
mCanSendData = false;
|
||||||
|
unused << SendStopSendingDataConfirmed();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MessagePortParent::RecvClose()
|
||||||
|
{
|
||||||
|
if (mService) {
|
||||||
|
MOZ_ASSERT(mEntangled);
|
||||||
|
|
||||||
|
if (!mService->ClosePort(this)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(!mEntangled);
|
||||||
|
|
||||||
|
unused << Send__delete__(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MessagePortParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||||
|
{
|
||||||
|
if (mService && mEntangled) {
|
||||||
|
// When the last parent is deleted, this service is freed but this cannot
|
||||||
|
// be done when the hashtables are written by CloseAll.
|
||||||
|
nsRefPtr<MessagePortService> kungFuDeathGrip = mService;
|
||||||
|
mService->ParentDestroy(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MessagePortParent::Entangled(const nsTArray<MessagePortMessage>& aMessages)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(!mEntangled);
|
||||||
|
mEntangled = true;
|
||||||
|
return SendEntangled(aMessages);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MessagePortParent::CloseAndDelete()
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
unused << Send__delete__(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MessagePortParent::Close()
|
||||||
|
{
|
||||||
|
mService = nullptr;
|
||||||
|
mEntangled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // dom namespace
|
||||||
|
} // mozilla namespace
|
|
@ -0,0 +1,61 @@
|
||||||
|
/* 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_MessagePortParent_h
|
||||||
|
#define mozilla_dom_MessagePortParent_h
|
||||||
|
|
||||||
|
#include "mozilla/dom/PMessagePortParent.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
class MessagePortService;
|
||||||
|
|
||||||
|
class MessagePortParent final : public PMessagePortParent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit MessagePortParent(const nsID& aUUID);
|
||||||
|
~MessagePortParent();
|
||||||
|
|
||||||
|
bool Entangle(const nsID& aDestinationUUID,
|
||||||
|
const uint32_t& aSequenceID);
|
||||||
|
|
||||||
|
bool Entangled(const nsTArray<MessagePortMessage>& aMessages);
|
||||||
|
|
||||||
|
void Close();
|
||||||
|
void CloseAndDelete();
|
||||||
|
|
||||||
|
bool CanSendData() const
|
||||||
|
{
|
||||||
|
return mCanSendData;
|
||||||
|
}
|
||||||
|
|
||||||
|
const nsID& ID() const
|
||||||
|
{
|
||||||
|
return mUUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual bool RecvPostMessages(nsTArray<MessagePortMessage>&& aMessages)
|
||||||
|
override;
|
||||||
|
|
||||||
|
virtual bool RecvDisentangle(nsTArray<MessagePortMessage>&& aMessages)
|
||||||
|
override;
|
||||||
|
|
||||||
|
virtual bool RecvStopSendingData() override;
|
||||||
|
|
||||||
|
virtual bool RecvClose() override;
|
||||||
|
|
||||||
|
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||||
|
|
||||||
|
nsRefPtr<MessagePortService> mService;
|
||||||
|
const nsID mUUID;
|
||||||
|
bool mEntangled;
|
||||||
|
bool mCanSendData;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // dom namespace
|
||||||
|
} // mozilla namespace
|
||||||
|
|
||||||
|
#endif // mozilla_dom_MessagePortParent_h
|
|
@ -0,0 +1,328 @@
|
||||||
|
/* -*- Mode: C++; 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/. */
|
||||||
|
|
||||||
|
#include "MessagePortService.h"
|
||||||
|
#include "MessagePortParent.h"
|
||||||
|
#include "SharedMessagePortMessage.h"
|
||||||
|
#include "mozilla/StaticPtr.h"
|
||||||
|
#include "mozilla/unused.h"
|
||||||
|
#include "nsDataHashtable.h"
|
||||||
|
#include "nsTArray.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
StaticRefPtr<MessagePortService> gInstance;
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
class MessagePortService::MessagePortServiceData final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit MessagePortServiceData(const nsID& aDestinationUUID)
|
||||||
|
: mDestinationUUID(aDestinationUUID)
|
||||||
|
, mSequenceID(1)
|
||||||
|
, mParent(nullptr)
|
||||||
|
{
|
||||||
|
MOZ_COUNT_CTOR(MessagePortServiceData);
|
||||||
|
}
|
||||||
|
|
||||||
|
MessagePortServiceData(const MessagePortServiceData& aOther) = delete;
|
||||||
|
MessagePortServiceData& operator=(const MessagePortServiceData&) = delete;
|
||||||
|
|
||||||
|
~MessagePortServiceData()
|
||||||
|
{
|
||||||
|
MOZ_COUNT_DTOR(MessagePortServiceData);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsID mDestinationUUID;
|
||||||
|
|
||||||
|
uint32_t mSequenceID;
|
||||||
|
MessagePortParent* mParent;
|
||||||
|
|
||||||
|
struct NextParent
|
||||||
|
{
|
||||||
|
uint32_t mSequenceID;
|
||||||
|
// MessagePortParent keeps the service alive, and we don't want a cycle.
|
||||||
|
MessagePortParent* mParent;
|
||||||
|
};
|
||||||
|
|
||||||
|
FallibleTArray<NextParent> mNextParents;
|
||||||
|
FallibleTArray<nsRefPtr<SharedMessagePortMessage>> mMessages;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* static */ MessagePortService*
|
||||||
|
MessagePortService::GetOrCreate()
|
||||||
|
{
|
||||||
|
if (!gInstance) {
|
||||||
|
gInstance = new MessagePortService();
|
||||||
|
}
|
||||||
|
|
||||||
|
return gInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MessagePortService::RequestEntangling(MessagePortParent* aParent,
|
||||||
|
const nsID& aDestinationUUID,
|
||||||
|
const uint32_t& aSequenceID)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aParent);
|
||||||
|
MessagePortServiceData* data;
|
||||||
|
|
||||||
|
// If we don't have a MessagePortServiceData, we must create 2 of them for
|
||||||
|
// both ports.
|
||||||
|
if (!mPorts.Get(aParent->ID(), &data)) {
|
||||||
|
// Create the MessagePortServiceData for the destination.
|
||||||
|
if (mPorts.Get(aDestinationUUID, nullptr)) {
|
||||||
|
MOZ_ASSERT(false, "The creation of the 2 ports should be in sync.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = new MessagePortServiceData(aParent->ID());
|
||||||
|
mPorts.Put(aDestinationUUID, data);
|
||||||
|
|
||||||
|
data = new MessagePortServiceData(aDestinationUUID);
|
||||||
|
mPorts.Put(aParent->ID(), data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a security check.
|
||||||
|
if (!data->mDestinationUUID.Equals(aDestinationUUID)) {
|
||||||
|
MOZ_ASSERT(false, "DestinationUUIDs do not match!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aSequenceID < data->mSequenceID) {
|
||||||
|
MOZ_ASSERT(false, "Invalid sequence ID!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aSequenceID == data->mSequenceID) {
|
||||||
|
if (data->mParent) {
|
||||||
|
MOZ_ASSERT(false, "Two ports cannot have the same sequenceID.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We activate this port, sending all the messages.
|
||||||
|
data->mParent = aParent;
|
||||||
|
FallibleTArray<MessagePortMessage> array;
|
||||||
|
if (!SharedMessagePortMessage::FromSharedToMessagesParent(aParent,
|
||||||
|
data->mMessages,
|
||||||
|
array)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->mMessages.Clear();
|
||||||
|
return aParent->Entangled(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This new parent will be the next one when a Disentangle request is
|
||||||
|
// received from the current parent.
|
||||||
|
MessagePortServiceData::NextParent* nextParent =
|
||||||
|
data->mNextParents.AppendElement(mozilla::fallible);
|
||||||
|
if (!nextParent) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
nextParent->mSequenceID = aSequenceID;
|
||||||
|
nextParent->mParent = aParent;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MessagePortService::DisentanglePort(
|
||||||
|
MessagePortParent* aParent,
|
||||||
|
FallibleTArray<nsRefPtr<SharedMessagePortMessage>>& aMessages)
|
||||||
|
{
|
||||||
|
MessagePortServiceData* data;
|
||||||
|
if (!mPorts.Get(aParent->ID(), &data)) {
|
||||||
|
MOZ_ASSERT(false, "Unknown MessagePortParent should not happen.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->mParent != aParent) {
|
||||||
|
MOZ_ASSERT(false, "DisentanglePort() should be called just from the correct parent.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let's put the messages in the correct order. |aMessages| contains the
|
||||||
|
// unsent messages so they have to go first.
|
||||||
|
if (!aMessages.AppendElements(data->mMessages, mozilla::fallible)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->mMessages.Clear();
|
||||||
|
|
||||||
|
++data->mSequenceID;
|
||||||
|
|
||||||
|
// If we don't have a parent, we have to store the pending messages and wait.
|
||||||
|
uint32_t index = 0;
|
||||||
|
MessagePortParent* nextParent = nullptr;
|
||||||
|
for (; index < data->mNextParents.Length(); ++index) {
|
||||||
|
if (data->mNextParents[index].mSequenceID == data->mSequenceID) {
|
||||||
|
nextParent = data->mNextParents[index].mParent;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We didn't find the parent.
|
||||||
|
if (!nextParent) {
|
||||||
|
data->mMessages.SwapElements(aMessages);
|
||||||
|
data->mParent = nullptr;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->mParent = nextParent;
|
||||||
|
data->mNextParents.RemoveElementAt(index);
|
||||||
|
|
||||||
|
FallibleTArray<MessagePortMessage> array;
|
||||||
|
if (!SharedMessagePortMessage::FromSharedToMessagesParent(data->mParent,
|
||||||
|
aMessages,
|
||||||
|
array)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
unused << data->mParent->Entangled(array);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MessagePortService::ClosePort(MessagePortParent* aParent)
|
||||||
|
{
|
||||||
|
MessagePortServiceData* data;
|
||||||
|
if (!mPorts.Get(aParent->ID(), &data)) {
|
||||||
|
MOZ_ASSERT(false, "Unknown MessagePortParent should not happend.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->mParent != aParent) {
|
||||||
|
MOZ_ASSERT(false, "ClosePort() should be called just from the correct parent.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data->mNextParents.IsEmpty()) {
|
||||||
|
MOZ_ASSERT(false, "ClosePort() should be called when there are not next parents.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't want to send a message to this parent.
|
||||||
|
data->mParent = nullptr;
|
||||||
|
|
||||||
|
CloseAll(aParent->ID());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
PLDHashOperator
|
||||||
|
MessagePortService::CloseAllDebugCheck(const nsID& aID,
|
||||||
|
MessagePortServiceData* aData,
|
||||||
|
void* aPtr)
|
||||||
|
{
|
||||||
|
nsID* id = static_cast<nsID*>(aPtr);
|
||||||
|
MOZ_ASSERT(!id->Equals(aID));
|
||||||
|
return PL_DHASH_NEXT;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
MessagePortService::CloseAll(const nsID& aUUID)
|
||||||
|
{
|
||||||
|
MessagePortServiceData* data;
|
||||||
|
if (!mPorts.Get(aUUID, &data)) {
|
||||||
|
MaybeShutdown();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->mParent) {
|
||||||
|
data->mParent->Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const MessagePortServiceData::NextParent& parent : data->mNextParents) {
|
||||||
|
parent.mParent->CloseAndDelete();
|
||||||
|
}
|
||||||
|
|
||||||
|
nsID destinationUUID = data->mDestinationUUID;
|
||||||
|
mPorts.Remove(aUUID);
|
||||||
|
|
||||||
|
CloseAll(destinationUUID);
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
mPorts.EnumerateRead(CloseAllDebugCheck, const_cast<nsID*>(&aUUID));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
MaybeShutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This service can be dismissed when there are not active ports.
|
||||||
|
void
|
||||||
|
MessagePortService::MaybeShutdown()
|
||||||
|
{
|
||||||
|
if (mPorts.Count() == 0) {
|
||||||
|
gInstance = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MessagePortService::PostMessages(
|
||||||
|
MessagePortParent* aParent,
|
||||||
|
FallibleTArray<nsRefPtr<SharedMessagePortMessage>>& aMessages)
|
||||||
|
{
|
||||||
|
MessagePortServiceData* data;
|
||||||
|
if (!mPorts.Get(aParent->ID(), &data)) {
|
||||||
|
MOZ_ASSERT(false, "Unknown MessagePortParent should not happend.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->mParent != aParent) {
|
||||||
|
MOZ_ASSERT(false, "PostMessages() should be called just from the correct parent.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ALWAYS_TRUE(mPorts.Get(data->mDestinationUUID, &data));
|
||||||
|
|
||||||
|
if (!data->mMessages.AppendElements(aMessages, mozilla::fallible)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the parent can send data to the child, let's proceed.
|
||||||
|
if (data->mParent && data->mParent->CanSendData()) {
|
||||||
|
FallibleTArray<MessagePortMessage> messages;
|
||||||
|
if (!SharedMessagePortMessage::FromSharedToMessagesParent(data->mParent,
|
||||||
|
data->mMessages,
|
||||||
|
messages)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->mMessages.Clear();
|
||||||
|
unused << data->mParent->SendReceiveData(messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MessagePortService::ParentDestroy(MessagePortParent* aParent)
|
||||||
|
{
|
||||||
|
// This port has already been destroyed.
|
||||||
|
MessagePortServiceData* data;
|
||||||
|
if (!mPorts.Get(aParent->ID(), &data)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->mParent != aParent) {
|
||||||
|
// We don't want to send a message to this parent.
|
||||||
|
for (uint32_t i = 0; i < data->mNextParents.Length(); ++i) {
|
||||||
|
if (aParent == data->mNextParents[i].mParent) {
|
||||||
|
data->mNextParents.RemoveElementAt(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseAll(aParent->ID());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // dom namespace
|
||||||
|
} // mozilla namespace
|
|
@ -0,0 +1,61 @@
|
||||||
|
/* 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_MessagePortService_h
|
||||||
|
#define mozilla_dom_MessagePortService_h
|
||||||
|
|
||||||
|
#include "nsClassHashtable.h"
|
||||||
|
#include "nsHashKeys.h"
|
||||||
|
#include "nsISupportsImpl.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
class MessagePortParent;
|
||||||
|
class SharedMessagePortMessage;
|
||||||
|
|
||||||
|
class MessagePortService final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NS_INLINE_DECL_REFCOUNTING(MessagePortService)
|
||||||
|
|
||||||
|
static MessagePortService* GetOrCreate();
|
||||||
|
|
||||||
|
bool RequestEntangling(MessagePortParent* aParent,
|
||||||
|
const nsID& aDestinationUUID,
|
||||||
|
const uint32_t& aSequenceID);
|
||||||
|
|
||||||
|
bool DisentanglePort(
|
||||||
|
MessagePortParent* aParent,
|
||||||
|
FallibleTArray<nsRefPtr<SharedMessagePortMessage>>& aMessages);
|
||||||
|
|
||||||
|
bool ClosePort(MessagePortParent* aParent);
|
||||||
|
|
||||||
|
bool PostMessages(
|
||||||
|
MessagePortParent* aParent,
|
||||||
|
FallibleTArray<nsRefPtr<SharedMessagePortMessage>>& aMessages);
|
||||||
|
|
||||||
|
void ParentDestroy(MessagePortParent* aParent);
|
||||||
|
|
||||||
|
private:
|
||||||
|
~MessagePortService() {}
|
||||||
|
|
||||||
|
void CloseAll(const nsID& aUUID);
|
||||||
|
void MaybeShutdown();
|
||||||
|
|
||||||
|
class MessagePortServiceData;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
static PLDHashOperator
|
||||||
|
CloseAllDebugCheck(const nsID& aID, MessagePortServiceData* aData,
|
||||||
|
void* aPtr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
nsClassHashtable<nsIDHashKey, MessagePortServiceData> mPorts;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // dom namespace
|
||||||
|
} // mozilla namespace
|
||||||
|
|
||||||
|
#endif // mozilla_dom_MessagePortService_h
|
|
@ -0,0 +1,277 @@
|
||||||
|
/* -*- Mode: C++; 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/. */
|
||||||
|
|
||||||
|
#include "MessagePortUtils.h"
|
||||||
|
#include "MessagePort.h"
|
||||||
|
#include "mozilla/dom/BlobBinding.h"
|
||||||
|
#include "mozilla/dom/File.h"
|
||||||
|
#include "mozilla/dom/MessagePortBinding.h"
|
||||||
|
#include "mozilla/dom/StructuredCloneTags.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace dom {
|
||||||
|
namespace messageport {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct MOZ_STACK_CLASS StructuredCloneClosureInternal
|
||||||
|
{
|
||||||
|
StructuredCloneClosureInternal(
|
||||||
|
StructuredCloneClosure& aClosure, nsPIDOMWindow* aWindow)
|
||||||
|
: mClosure(aClosure)
|
||||||
|
, mWindow(aWindow)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
StructuredCloneClosure& mClosure;
|
||||||
|
nsPIDOMWindow* mWindow;
|
||||||
|
nsTArray<nsRefPtr<MessagePort>> mMessagePorts;
|
||||||
|
nsTArray<nsRefPtr<MessagePortBase>> mTransferredPorts;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MOZ_STACK_CLASS StructuredCloneClosureInternalReadOnly
|
||||||
|
{
|
||||||
|
StructuredCloneClosureInternalReadOnly(
|
||||||
|
const StructuredCloneClosure& aClosure, nsPIDOMWindow* aWindow)
|
||||||
|
: mClosure(aClosure)
|
||||||
|
, mWindow(aWindow)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
const StructuredCloneClosure& mClosure;
|
||||||
|
nsPIDOMWindow* mWindow;
|
||||||
|
nsTArray<nsRefPtr<MessagePort>> mMessagePorts;
|
||||||
|
nsTArray<nsRefPtr<MessagePortBase>> mTransferredPorts;
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
Error(JSContext* aCx, uint32_t aErrorId)
|
||||||
|
{
|
||||||
|
if (NS_IsMainThread()) {
|
||||||
|
NS_DOMStructuredCloneError(aCx, aErrorId);
|
||||||
|
} else {
|
||||||
|
Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JSObject*
|
||||||
|
Read(JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag,
|
||||||
|
uint32_t aData, void* aClosure)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aClosure);
|
||||||
|
|
||||||
|
auto* closure = static_cast<StructuredCloneClosureInternalReadOnly*>(aClosure);
|
||||||
|
|
||||||
|
if (aTag == SCTAG_DOM_BLOB) {
|
||||||
|
// nsRefPtr<File> needs to go out of scope before toObjectOrNull() is
|
||||||
|
// called because the static analysis thinks dereferencing XPCOM objects
|
||||||
|
// can GC (because in some cases it can!), and a return statement with a
|
||||||
|
// JSObject* type means that JSObject* is on the stack as a raw pointer
|
||||||
|
// while destructors are running.
|
||||||
|
JS::Rooted<JS::Value> val(aCx);
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aData < closure->mClosure.mBlobImpls.Length());
|
||||||
|
nsRefPtr<BlobImpl> blobImpl = closure->mClosure.mBlobImpls[aData];
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
{
|
||||||
|
// Blob should not be mutable.
|
||||||
|
bool isMutable;
|
||||||
|
MOZ_ASSERT(NS_SUCCEEDED(blobImpl->GetMutable(&isMutable)));
|
||||||
|
MOZ_ASSERT(!isMutable);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Let's create a new blob with the correct parent.
|
||||||
|
nsIGlobalObject* global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
|
||||||
|
MOZ_ASSERT(global);
|
||||||
|
|
||||||
|
nsRefPtr<Blob> newBlob = Blob::Create(global, blobImpl);
|
||||||
|
if (!ToJSValue(aCx, newBlob, &val)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &val.toObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_DOMReadStructuredClone(aCx, aReader, aTag, aData, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Write(JSContext* aCx, JSStructuredCloneWriter* aWriter,
|
||||||
|
JS::Handle<JSObject*> aObj, void* aClosure)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aClosure);
|
||||||
|
|
||||||
|
auto* closure = static_cast<StructuredCloneClosureInternal*>(aClosure);
|
||||||
|
|
||||||
|
// See if the wrapped native is a File/Blob.
|
||||||
|
{
|
||||||
|
Blob* blob = nullptr;
|
||||||
|
if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob)) &&
|
||||||
|
NS_SUCCEEDED(blob->SetMutable(false)) &&
|
||||||
|
JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB,
|
||||||
|
closure->mClosure.mBlobImpls.Length())) {
|
||||||
|
closure->mClosure.mBlobImpls.AppendElement(blob->Impl());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_DOMWriteStructuredClone(aCx, aWriter, aObj, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ReadTransfer(JSContext* aCx, JSStructuredCloneReader* aReader,
|
||||||
|
uint32_t aTag, void* aContent, uint64_t aExtraData,
|
||||||
|
void* aClosure, JS::MutableHandle<JSObject*> aReturnObject)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
MOZ_ASSERT(aClosure);
|
||||||
|
|
||||||
|
auto* closure = static_cast<StructuredCloneClosureInternalReadOnly*>(aClosure);
|
||||||
|
|
||||||
|
if (aTag != SCTAG_DOM_MAP_MESSAGEPORT) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(aContent == 0);
|
||||||
|
MOZ_ASSERT(aExtraData < closure->mClosure.mMessagePortIdentifiers.Length());
|
||||||
|
|
||||||
|
ErrorResult rv;
|
||||||
|
nsRefPtr<MessagePort> port =
|
||||||
|
MessagePort::Create(closure->mWindow,
|
||||||
|
closure->mClosure.mMessagePortIdentifiers[(uint32_t)aExtraData],
|
||||||
|
rv);
|
||||||
|
if (NS_WARN_IF(rv.Failed())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
closure->mMessagePorts.AppendElement(port);
|
||||||
|
|
||||||
|
JS::Rooted<JS::Value> value(aCx);
|
||||||
|
if (!GetOrCreateDOMReflector(aCx, port, &value)) {
|
||||||
|
JS_ClearPendingException(aCx);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
aReturnObject.set(&value.toObject());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
WriteTransfer(JSContext* aCx, JS::Handle<JSObject*> aObj, void* aClosure,
|
||||||
|
uint32_t* aTag, JS::TransferableOwnership* aOwnership,
|
||||||
|
void** aContent, uint64_t* aExtraData)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aClosure);
|
||||||
|
|
||||||
|
auto* closure = static_cast<StructuredCloneClosureInternal*>(aClosure);
|
||||||
|
|
||||||
|
MessagePortBase* port = nullptr;
|
||||||
|
nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (closure->mTransferredPorts.Contains(port)) {
|
||||||
|
// No duplicates.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MessagePortIdentifier identifier;
|
||||||
|
if (!port->CloneAndDisentangle(identifier)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
closure->mClosure.mMessagePortIdentifiers.AppendElement(identifier);
|
||||||
|
closure->mTransferredPorts.AppendElement(port);
|
||||||
|
|
||||||
|
*aTag = SCTAG_DOM_MAP_MESSAGEPORT;
|
||||||
|
*aOwnership = JS::SCTAG_TMO_CUSTOM;
|
||||||
|
*aContent = nullptr;
|
||||||
|
*aExtraData = closure->mClosure.mMessagePortIdentifiers.Length() - 1;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const JSStructuredCloneCallbacks gCallbacks = {
|
||||||
|
Read,
|
||||||
|
Write,
|
||||||
|
Error,
|
||||||
|
ReadTransfer,
|
||||||
|
WriteTransfer,
|
||||||
|
nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
bool
|
||||||
|
ReadStructuredCloneWithTransfer(JSContext* aCx, nsTArray<uint8_t>& aData,
|
||||||
|
const StructuredCloneClosure& aClosure,
|
||||||
|
JS::MutableHandle<JS::Value> aClone,
|
||||||
|
nsPIDOMWindow* aParentWindow,
|
||||||
|
nsTArray<nsRefPtr<MessagePort>>& aMessagePorts)
|
||||||
|
{
|
||||||
|
auto* data = reinterpret_cast<uint64_t*>(aData.Elements());
|
||||||
|
size_t dataLen = aData.Length();
|
||||||
|
MOZ_ASSERT(!(dataLen % sizeof(*data)));
|
||||||
|
|
||||||
|
StructuredCloneClosureInternalReadOnly internalClosure(aClosure,
|
||||||
|
aParentWindow);
|
||||||
|
|
||||||
|
bool rv = JS_ReadStructuredClone(aCx, data, dataLen,
|
||||||
|
JS_STRUCTURED_CLONE_VERSION, aClone,
|
||||||
|
&gCallbacks, &internalClosure);
|
||||||
|
if (rv) {
|
||||||
|
aMessagePorts.SwapElements(internalClosure.mMessagePorts);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
WriteStructuredCloneWithTransfer(JSContext* aCx, JS::Handle<JS::Value> aSource,
|
||||||
|
JS::Handle<JS::Value> aTransferable,
|
||||||
|
nsTArray<uint8_t>& aData,
|
||||||
|
StructuredCloneClosure& aClosure)
|
||||||
|
{
|
||||||
|
StructuredCloneClosureInternal internalClosure(aClosure, nullptr);
|
||||||
|
JSAutoStructuredCloneBuffer buffer(&gCallbacks, &internalClosure);
|
||||||
|
|
||||||
|
if (!buffer.write(aCx, aSource, aTransferable, &gCallbacks,
|
||||||
|
&internalClosure)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FallibleTArray<uint8_t> cloneData;
|
||||||
|
if (NS_WARN_IF(!cloneData.SetLength(buffer.nbytes(), mozilla::fallible))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t* data;
|
||||||
|
size_t size;
|
||||||
|
buffer.steal(&data, &size);
|
||||||
|
|
||||||
|
memcpy(cloneData.Elements(), data, size);
|
||||||
|
js_free(data);
|
||||||
|
|
||||||
|
MOZ_ASSERT(aData.IsEmpty());
|
||||||
|
aData.SwapElements(cloneData);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
FreeStructuredClone(nsTArray<uint8_t>& aData, StructuredCloneClosure& aClosure)
|
||||||
|
{
|
||||||
|
auto* data = reinterpret_cast<uint64_t*>(aData.Elements());
|
||||||
|
size_t dataLen = aData.Length();
|
||||||
|
MOZ_ASSERT(!(dataLen % sizeof(*data)));
|
||||||
|
|
||||||
|
JS_ClearStructuredClone(data, dataLen, &gCallbacks, &aClosure, false);
|
||||||
|
aData.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // messageport namespace
|
||||||
|
} // dom namespace
|
||||||
|
} // mozilla namespace
|
|
@ -0,0 +1,55 @@
|
||||||
|
/* 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_MessagePortUtils_h
|
||||||
|
#define mozilla_dom_MessagePortUtils_h
|
||||||
|
|
||||||
|
#include "MessagePort.h"
|
||||||
|
#include "mozilla/dom/File.h"
|
||||||
|
#include "mozilla/dom/PMessagePort.h"
|
||||||
|
|
||||||
|
class nsPIDOMWindow;
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace dom {
|
||||||
|
namespace messageport {
|
||||||
|
|
||||||
|
struct
|
||||||
|
StructuredCloneClosure
|
||||||
|
{
|
||||||
|
nsTArray<nsRefPtr<BlobImpl>> mBlobImpls;
|
||||||
|
nsTArray<MessagePortIdentifier> mMessagePortIdentifiers;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct
|
||||||
|
StructuredCloneData
|
||||||
|
{
|
||||||
|
StructuredCloneData() : mData(nullptr), mDataLength(0) {}
|
||||||
|
uint64_t* mData;
|
||||||
|
size_t mDataLength;
|
||||||
|
StructuredCloneClosure mClosure;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool
|
||||||
|
ReadStructuredCloneWithTransfer(JSContext* aCx, nsTArray<uint8_t>& aData,
|
||||||
|
const StructuredCloneClosure& aClosure,
|
||||||
|
JS::MutableHandle<JS::Value> aClone,
|
||||||
|
nsPIDOMWindow* aParentWindow,
|
||||||
|
nsTArray<nsRefPtr<MessagePort>>& aMessagePorts);
|
||||||
|
|
||||||
|
bool
|
||||||
|
WriteStructuredCloneWithTransfer(JSContext* aCx, JS::Handle<JS::Value> aSource,
|
||||||
|
JS::Handle<JS::Value> aTransferable,
|
||||||
|
nsTArray<uint8_t>& aData,
|
||||||
|
StructuredCloneClosure& aClosure);
|
||||||
|
|
||||||
|
void
|
||||||
|
FreeStructuredClone(nsTArray<uint8_t>& aData,
|
||||||
|
StructuredCloneClosure& aClosure);
|
||||||
|
|
||||||
|
} // messageport namespace
|
||||||
|
} // dom namespace
|
||||||
|
} // mozilla namespace
|
||||||
|
|
||||||
|
#endif // mozilla_dom_MessagePortUtils_h
|
|
@ -0,0 +1,62 @@
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
using struct nsID from "nsID.h";
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
struct MessagePortIdentifier
|
||||||
|
{
|
||||||
|
nsID uuid;
|
||||||
|
nsID destinationUuid;
|
||||||
|
uint32_t sequenceId;
|
||||||
|
bool neutered;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MessagePortMessage
|
||||||
|
{
|
||||||
|
MessagePortIdentifier[] transferredPorts;
|
||||||
|
uint8_t[] data;
|
||||||
|
PBlob[] blobs;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This protocol is used for the MessageChannel/MessagePort API
|
||||||
|
protocol PMessagePort
|
||||||
|
{
|
||||||
|
manager PBackground;
|
||||||
|
|
||||||
|
/* Many of these methods are used just for the shutdown sequence. The
|
||||||
|
correct sequence for the child actor is:
|
||||||
|
1. SendStopSendingData();
|
||||||
|
2. RecvStopSendingDataConfirmed();
|
||||||
|
3. SendClose();
|
||||||
|
4. Recv__delete__(); */
|
||||||
|
|
||||||
|
/* When the port is transferred the sequence is:
|
||||||
|
1. SendStopSendingData();
|
||||||
|
2. RecvStopSendingDataConfirmed();
|
||||||
|
3. SendDisentangle();
|
||||||
|
4. Recv__delete__(); */
|
||||||
|
|
||||||
|
parent:
|
||||||
|
PostMessages(MessagePortMessage[] messages);
|
||||||
|
Disentangle(MessagePortMessage[] messages);
|
||||||
|
StopSendingData();
|
||||||
|
Close();
|
||||||
|
|
||||||
|
child:
|
||||||
|
Entangled(MessagePortMessage[] messages);
|
||||||
|
ReceiveData(MessagePortMessage[] messages);
|
||||||
|
StopSendingDataConfirmed();
|
||||||
|
|
||||||
|
__delete__();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace dom
|
||||||
|
} // namespace mozilla
|
||||||
|
|
|
@ -0,0 +1,180 @@
|
||||||
|
/* -*- Mode: C++; 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/. */
|
||||||
|
|
||||||
|
#include "SharedMessagePortMessage.h"
|
||||||
|
#include "MessagePort.h"
|
||||||
|
#include "MessagePortChild.h"
|
||||||
|
#include "MessagePortParent.h"
|
||||||
|
#include "mozilla/dom/ipc/BlobChild.h"
|
||||||
|
#include "mozilla/dom/ipc/BlobParent.h"
|
||||||
|
#include "mozilla/dom/File.h"
|
||||||
|
#include "mozilla/dom/PMessagePort.h"
|
||||||
|
#include "mozilla/ipc/BackgroundChild.h"
|
||||||
|
#include "mozilla/ipc/BackgroundParent.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
|
using namespace ipc;
|
||||||
|
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
SharedMessagePortMessage::~SharedMessagePortMessage()
|
||||||
|
{
|
||||||
|
if (!mData.IsEmpty()) {
|
||||||
|
FreeStructuredClone(mData, mClosure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */ void
|
||||||
|
SharedMessagePortMessage::FromSharedToMessagesChild(
|
||||||
|
MessagePortChild* aActor,
|
||||||
|
const nsTArray<nsRefPtr<SharedMessagePortMessage>>& aData,
|
||||||
|
nsTArray<MessagePortMessage>& aArray)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aActor);
|
||||||
|
MOZ_ASSERT(aArray.IsEmpty());
|
||||||
|
aArray.SetCapacity(aData.Length());
|
||||||
|
|
||||||
|
PBackgroundChild* backgroundManager = aActor->Manager();
|
||||||
|
MOZ_ASSERT(backgroundManager);
|
||||||
|
|
||||||
|
for (auto& data : aData) {
|
||||||
|
MessagePortMessage* message = aArray.AppendElement();
|
||||||
|
message->data().SwapElements(data->mData);
|
||||||
|
|
||||||
|
const nsTArray<nsRefPtr<BlobImpl>>& blobImpls =
|
||||||
|
data->mClosure.mBlobImpls;
|
||||||
|
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]);
|
||||||
|
message->blobsChild().AppendElement(blobChild);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message->transferredPorts().AppendElements(
|
||||||
|
data->mClosure.mMessagePortIdentifiers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */ bool
|
||||||
|
SharedMessagePortMessage::FromMessagesToSharedChild(
|
||||||
|
nsTArray<MessagePortMessage>& aArray,
|
||||||
|
FallibleTArray<nsRefPtr<SharedMessagePortMessage>>& aData)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aData.IsEmpty());
|
||||||
|
|
||||||
|
if (NS_WARN_IF(!aData.SetCapacity(aArray.Length(), mozilla::fallible))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& message : aArray) {
|
||||||
|
nsRefPtr<SharedMessagePortMessage> data = new SharedMessagePortMessage();
|
||||||
|
|
||||||
|
data->mData.SwapElements(message.data());
|
||||||
|
|
||||||
|
const nsTArray<PBlobChild*>& blobs = message.blobsChild();
|
||||||
|
if (!blobs.IsEmpty()) {
|
||||||
|
data->mClosure.mBlobImpls.SetCapacity(blobs.Length());
|
||||||
|
|
||||||
|
for (uint32_t i = 0, len = blobs.Length(); i < len; ++i) {
|
||||||
|
nsRefPtr<BlobImpl> impl =
|
||||||
|
static_cast<BlobChild*>(blobs[i])->GetBlobImpl();
|
||||||
|
data->mClosure.mBlobImpls.AppendElement(impl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data->mClosure.mMessagePortIdentifiers.AppendElements(
|
||||||
|
message.transferredPorts());
|
||||||
|
|
||||||
|
if (!aData.AppendElement(data, mozilla::fallible)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */ bool
|
||||||
|
SharedMessagePortMessage::FromSharedToMessagesParent(
|
||||||
|
MessagePortParent* aActor,
|
||||||
|
const nsTArray<nsRefPtr<SharedMessagePortMessage>>& aData,
|
||||||
|
FallibleTArray<MessagePortMessage>& aArray)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aArray.IsEmpty());
|
||||||
|
|
||||||
|
if (NS_WARN_IF(!aArray.SetCapacity(aData.Length(), mozilla::fallible))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PBackgroundParent* backgroundManager = aActor->Manager();
|
||||||
|
MOZ_ASSERT(backgroundManager);
|
||||||
|
|
||||||
|
for (auto& data : aData) {
|
||||||
|
MessagePortMessage* message = aArray.AppendElement(mozilla::fallible);
|
||||||
|
message->data().SwapElements(data->mData);
|
||||||
|
|
||||||
|
const nsTArray<nsRefPtr<BlobImpl>>& blobImpls = data->mClosure.mBlobImpls;
|
||||||
|
if (!blobImpls.IsEmpty()) {
|
||||||
|
message->blobsParent().SetCapacity(blobImpls.Length());
|
||||||
|
|
||||||
|
for (uint32_t i = 0, len = blobImpls.Length(); i < len; ++i) {
|
||||||
|
PBlobParent* blobParent =
|
||||||
|
BackgroundParent::GetOrCreateActorForBlobImpl(backgroundManager,
|
||||||
|
blobImpls[i]);
|
||||||
|
message->blobsParent().AppendElement(blobParent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message->transferredPorts().AppendElements(
|
||||||
|
data->mClosure.mMessagePortIdentifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */ bool
|
||||||
|
SharedMessagePortMessage::FromMessagesToSharedParent(
|
||||||
|
nsTArray<MessagePortMessage>& aArray,
|
||||||
|
FallibleTArray<nsRefPtr<SharedMessagePortMessage>>& aData)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aData.IsEmpty());
|
||||||
|
|
||||||
|
if (NS_WARN_IF(!aData.SetCapacity(aArray.Length(), mozilla::fallible))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& message : aArray) {
|
||||||
|
nsRefPtr<SharedMessagePortMessage> data = new SharedMessagePortMessage();
|
||||||
|
|
||||||
|
data->mData.SwapElements(message.data());
|
||||||
|
|
||||||
|
const nsTArray<PBlobParent*>& blobs = message.blobsParent();
|
||||||
|
if (!blobs.IsEmpty()) {
|
||||||
|
data->mClosure.mBlobImpls.SetCapacity(blobs.Length());
|
||||||
|
|
||||||
|
for (uint32_t i = 0, len = blobs.Length(); i < len; ++i) {
|
||||||
|
nsRefPtr<BlobImpl> impl =
|
||||||
|
static_cast<BlobParent*>(blobs[i])->GetBlobImpl();
|
||||||
|
data->mClosure.mBlobImpls.AppendElement(impl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data->mClosure.mMessagePortIdentifiers.AppendElements(
|
||||||
|
message.transferredPorts());
|
||||||
|
|
||||||
|
if (!aData.AppendElement(data, mozilla::fallible)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // dom namespace
|
||||||
|
} // mozilla namespace
|
|
@ -0,0 +1,58 @@
|
||||||
|
/* -*- Mode: C++; 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/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_dom_SharedMessagePortMessage_h
|
||||||
|
#define mozilla_dom_SharedMessagePortMessage_h
|
||||||
|
|
||||||
|
#include "MessagePortUtils.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
class MessagePortChild;
|
||||||
|
class MessagePortMessage;
|
||||||
|
class MessagePortParent;
|
||||||
|
|
||||||
|
class SharedMessagePortMessage final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NS_INLINE_DECL_REFCOUNTING(SharedMessagePortMessage)
|
||||||
|
|
||||||
|
nsTArray<uint8_t> mData;
|
||||||
|
messageport::StructuredCloneClosure mClosure;
|
||||||
|
|
||||||
|
SharedMessagePortMessage()
|
||||||
|
{}
|
||||||
|
|
||||||
|
static void
|
||||||
|
FromSharedToMessagesChild(
|
||||||
|
MessagePortChild* aActor,
|
||||||
|
const nsTArray<nsRefPtr<SharedMessagePortMessage>>& aData,
|
||||||
|
nsTArray<MessagePortMessage>& aArray);
|
||||||
|
|
||||||
|
static bool
|
||||||
|
FromMessagesToSharedChild(
|
||||||
|
nsTArray<MessagePortMessage>& aArray,
|
||||||
|
FallibleTArray<nsRefPtr<SharedMessagePortMessage>>& aData);
|
||||||
|
|
||||||
|
static bool
|
||||||
|
FromSharedToMessagesParent(
|
||||||
|
MessagePortParent* aActor,
|
||||||
|
const nsTArray<nsRefPtr<SharedMessagePortMessage>>& aData,
|
||||||
|
FallibleTArray<MessagePortMessage>& aArray);
|
||||||
|
|
||||||
|
static bool
|
||||||
|
FromMessagesToSharedParent(
|
||||||
|
nsTArray<MessagePortMessage>& aArray,
|
||||||
|
FallibleTArray<nsRefPtr<SharedMessagePortMessage>>& aData);
|
||||||
|
|
||||||
|
private:
|
||||||
|
~SharedMessagePortMessage();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // dom namespace
|
||||||
|
} // mozilla namespace
|
||||||
|
|
||||||
|
#endif // mozilla_dom_SharedMessagePortMessage_h
|
|
@ -0,0 +1,41 @@
|
||||||
|
# -*- Mode: python; c-basic-offset: 4; 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/.
|
||||||
|
|
||||||
|
TEST_DIRS += ['tests']
|
||||||
|
|
||||||
|
EXPORTS.mozilla.dom += [
|
||||||
|
'MessageChannel.h',
|
||||||
|
'MessagePort.h',
|
||||||
|
'MessagePortChild.h',
|
||||||
|
'MessagePortList.h',
|
||||||
|
'MessagePortParent.h',
|
||||||
|
]
|
||||||
|
|
||||||
|
UNIFIED_SOURCES += [
|
||||||
|
'MessageChannel.cpp',
|
||||||
|
'MessagePort.cpp',
|
||||||
|
'MessagePortChild.cpp',
|
||||||
|
'MessagePortList.cpp',
|
||||||
|
'MessagePortParent.cpp',
|
||||||
|
'MessagePortService.cpp',
|
||||||
|
'MessagePortUtils.cpp',
|
||||||
|
'SharedMessagePortMessage.cpp',
|
||||||
|
]
|
||||||
|
|
||||||
|
IPDL_SOURCES += [
|
||||||
|
'PMessagePort.ipdl',
|
||||||
|
]
|
||||||
|
|
||||||
|
LOCAL_INCLUDES += [
|
||||||
|
'../base',
|
||||||
|
'../events',
|
||||||
|
'../workers',
|
||||||
|
]
|
||||||
|
|
||||||
|
include('/ipc/chromium/chromium-config.mozbuild')
|
||||||
|
|
||||||
|
FINAL_LIBRARY = 'xul'
|
||||||
|
FAIL_ON_WARNINGS = True
|
|
@ -0,0 +1,5 @@
|
||||||
|
[DEFAULT]
|
||||||
|
support-files =
|
||||||
|
iframe_messageChannel_chrome.html
|
||||||
|
|
||||||
|
[test_messageChannel.xul]
|
|
@ -0,0 +1,14 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<script type="application/javascript">
|
||||||
|
|
||||||
|
var a = new SharedWorker('sharedWorker2_messageChannel.js');
|
||||||
|
a.port.onmessage = function(evt) {
|
||||||
|
evt.ports[0].postMessage("Hello from the iframe!");
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<script type="application/javascript">
|
||||||
|
|
||||||
|
function ok(what, msg) {
|
||||||
|
window.parent.postMessage({type: what ? 'OK' : 'KO', msg: msg }, '*');
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('message', receiveMessage, false);
|
||||||
|
function receiveMessage(evt) {
|
||||||
|
ok(evt.ports.length == 1, "Port transferred!");
|
||||||
|
|
||||||
|
var a = new MessageChannel();
|
||||||
|
ok(a, "MessageChannel created");
|
||||||
|
evt.ports[0].postMessage('hello world!', [a.port2]);
|
||||||
|
a.port1.onmessage = function(evt) {
|
||||||
|
evt.target.postMessage(evt.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
[DEFAULT]
|
||||||
|
support-files =
|
||||||
|
iframe_messageChannel_cloning.html
|
||||||
|
iframe_messageChannel_pingpong.html
|
||||||
|
iframe_messageChannel_post.html
|
||||||
|
iframe_messageChannel_transferable.html
|
||||||
|
worker_messageChannel.js
|
||||||
|
worker_messageChannel_any.js
|
||||||
|
sharedWorker_messageChannel.js
|
||||||
|
sharedWorker2_messageChannel.js
|
||||||
|
iframe_messageChannel_sharedWorker2.html
|
||||||
|
|
||||||
|
[test_messageChannel.html]
|
||||||
|
[test_messageChannel_cloning.html]
|
||||||
|
[test_messageChannel_pingpong.html]
|
||||||
|
[test_messageChannel_post.html]
|
||||||
|
[test_messageChannel_pref.html]
|
||||||
|
[test_messageChannel_start.html]
|
||||||
|
[test_messageChannel_transferable.html]
|
||||||
|
[test_messageChannel_unshipped.html]
|
||||||
|
[test_messageChannel_worker.html]
|
||||||
|
[test_messageChannel_selfTransferring.html]
|
||||||
|
[test_messageChannel_sharedWorker.html]
|
||||||
|
[test_messageChannel_sharedWorker2.html]
|
||||||
|
[test_messageChannel_any.html]
|
|
@ -0,0 +1,8 @@
|
||||||
|
# -*- Mode: python; c-basic-offset: 4; 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/.
|
||||||
|
|
||||||
|
MOCHITEST_MANIFESTS += ['mochitest.ini']
|
||||||
|
MOCHITEST_CHROME_MANIFESTS += ['chrome.ini']
|
|
@ -0,0 +1,7 @@
|
||||||
|
var mc = new MessageChannel();
|
||||||
|
var i = 0;
|
||||||
|
|
||||||
|
onconnect = function(evt) {
|
||||||
|
dump("CONNECTING: "+ i +"\n");
|
||||||
|
evt.ports[0].postMessage(42, [mc['port' + ++i]]);
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
onconnect = function(evt) {
|
||||||
|
var mc = new MessageChannel();
|
||||||
|
|
||||||
|
evt.ports[0].postMessage(42, [mc.port2]);
|
||||||
|
mc.port1.onmessage = function(e) {
|
||||||
|
mc.port1.postMessage(e.data);
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,7 +23,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
var ifr = document.createElement('browser');
|
var ifr = document.createElement('browser');
|
||||||
ifr.setAttribute("src", "http://mochi.test:8888/tests/dom/base/test/iframe_messageChannel_chrome.html");
|
ifr.setAttribute("src", "iframe_messageChannel_chrome.html");
|
||||||
ifr.setAttribute("flex", "1");
|
ifr.setAttribute("flex", "1");
|
||||||
ifr.addEventListener('load', function() {
|
ifr.addEventListener('load', function() {
|
||||||
ifr.contentWindow.postMessage(channel.port2, '*', [channel.port2]);
|
ifr.contentWindow.postMessage(channel.port2, '*', [channel.port2]);
|
|
@ -0,0 +1,115 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<!--
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=677638
|
||||||
|
-->
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>MessagePort/Channel any content</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">
|
||||||
|
|
||||||
|
var tests = [
|
||||||
|
'hello world',
|
||||||
|
123,
|
||||||
|
null,
|
||||||
|
true,
|
||||||
|
new Date(),
|
||||||
|
[ 1, 'test', true, new Date() ],
|
||||||
|
{ a: true, b: null, c: new Date(), d: [ true, false, {} ] },
|
||||||
|
new Blob([123], { type: 'plain/text' })
|
||||||
|
];
|
||||||
|
|
||||||
|
var currentTest = null;
|
||||||
|
|
||||||
|
function getType(a) {
|
||||||
|
if (a === null || a === undefined)
|
||||||
|
return 'null';
|
||||||
|
|
||||||
|
if (Array.isArray(a))
|
||||||
|
return 'array';
|
||||||
|
|
||||||
|
if (typeof a == 'object')
|
||||||
|
return 'object';
|
||||||
|
|
||||||
|
return 'primitive';
|
||||||
|
}
|
||||||
|
|
||||||
|
function compare(a, b) {
|
||||||
|
is (getType(a), getType(b), 'Type matches');
|
||||||
|
|
||||||
|
var type = getType(a);
|
||||||
|
if (type == 'array') {
|
||||||
|
is (a.length, b.length, 'Array.length matches');
|
||||||
|
for (var i = 0; i < a.length; ++i) {
|
||||||
|
compare(a[i], b[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == 'object') {
|
||||||
|
ok (a !== b, 'They should not match');
|
||||||
|
|
||||||
|
var aProps = [];
|
||||||
|
for (var p in a) aProps.push(p);
|
||||||
|
|
||||||
|
var bProps = [];
|
||||||
|
for (var p in b) bProps.push(p);
|
||||||
|
|
||||||
|
is (aProps.length, bProps.length, 'Props match');
|
||||||
|
is (aProps.sort().toSource(), bProps.sort().toSource(), 'Props match - using toSource()');
|
||||||
|
|
||||||
|
for (var p in a) {
|
||||||
|
compare(a[p], b[p]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type != 'null') {
|
||||||
|
is (a.toSource(), b.toSource(), 'Matching using toSource()');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function runTest() {
|
||||||
|
var mc = new MessageChannel('foobar');
|
||||||
|
ok(mc, "MessageChannel can be created");
|
||||||
|
|
||||||
|
mc.port1.onmessage = function(event) {
|
||||||
|
compare(event.data, currentTest);
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
|
||||||
|
function next() {
|
||||||
|
if (!tests.length) {
|
||||||
|
SimpleTest.finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentTest = tests.shift();
|
||||||
|
mc.port1.postMessage(currentTest);
|
||||||
|
}
|
||||||
|
|
||||||
|
var worker = new Worker("worker_messageChannel_any.js");
|
||||||
|
worker.onmessage = function(event) {
|
||||||
|
if (event.data == "READY") {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
worker.postMessage(mc.port2, [mc.port2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
SpecialPowers.pushPrefEnv({"set": [["dom.messageChannel.enabled", true]]}, runTest);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,38 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<!--
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=677638
|
||||||
|
-->
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>MessagePort/Channel no self tranferring</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">
|
||||||
|
|
||||||
|
function runTest() {
|
||||||
|
var a = new MessageChannel();
|
||||||
|
|
||||||
|
var status = false;
|
||||||
|
try {
|
||||||
|
a.port1.postMessage('foobar', [a.port1]);
|
||||||
|
} catch(e) {
|
||||||
|
status =true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok(status, "Transfering the same port should throw");
|
||||||
|
SimpleTest.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
SpecialPowers.pushPrefEnv({"set": [["dom.messageChannel.enabled", true]]}, runTest);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<!--
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=677638
|
||||||
|
-->
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Test for Bug 677638 - sharedWorker</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>
|
||||||
|
<p id="display"></p>
|
||||||
|
<div id="content" style="display: none">
|
||||||
|
<iframe name="x" id="x"></iframe>
|
||||||
|
<iframe name="y" id="y"></iframe>
|
||||||
|
</div>
|
||||||
|
<pre id="test">
|
||||||
|
</pre>
|
||||||
|
<script type="application/javascript">
|
||||||
|
|
||||||
|
function runTest() {
|
||||||
|
var a = new SharedWorker('sharedWorker_messageChannel.js');
|
||||||
|
a.port.onmessage = function(evt) {
|
||||||
|
is(evt.ports.length, 1, "We received a port.");
|
||||||
|
evt.ports[0].onmessage = function(e) {
|
||||||
|
is(e.data, 42, "Message reiceved back!");
|
||||||
|
SimpleTest.finish();
|
||||||
|
}
|
||||||
|
evt.ports[0].postMessage(42);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SpecialPowers.pushPrefEnv({"set": [["dom.messageChannel.enabled", true]]}, runTest);
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,37 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<!--
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=677638
|
||||||
|
-->
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Test for Bug 677638 - sharedWorker</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>
|
||||||
|
|
||||||
|
<script type="application/javascript">
|
||||||
|
|
||||||
|
function runTest() {
|
||||||
|
var iframe = document.createElement('iframe');
|
||||||
|
iframe.setAttribute('src', "iframe_messageChannel_sharedWorker2.html");
|
||||||
|
document.getElementById('content').appendChild(iframe);
|
||||||
|
|
||||||
|
var a = new SharedWorker('sharedWorker2_messageChannel.js');
|
||||||
|
a.port.onmessage = function(evt) {
|
||||||
|
is(evt.ports.length, 1, "We received a port.");
|
||||||
|
evt.ports[0].onmessage = function(e) {
|
||||||
|
is(e.data, "Hello from the iframe!", "Message reiceved from the iframe!");
|
||||||
|
SimpleTest.finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SpecialPowers.pushPrefEnv({"set": [["dom.messageChannel.enabled", true]]}, runTest);
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -16,14 +16,15 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=677638
|
||||||
</pre>
|
</pre>
|
||||||
<script type="application/javascript">
|
<script type="application/javascript">
|
||||||
|
|
||||||
function start() {
|
function basic_test() {
|
||||||
var a = new MessageChannel();
|
var a = new MessageChannel();
|
||||||
ok(a, "MessageChannel created");
|
ok(a, "MessageChannel created");
|
||||||
|
|
||||||
window.addEventListener('message', receiveMessage, false);
|
window.addEventListener('message', receiveMessage, false);
|
||||||
function receiveMessage(evt) {
|
function receiveMessage(evt) {
|
||||||
if (evt.data.status == 'READY') {
|
if (evt.data.status == 'READY') {
|
||||||
runTest();
|
a.port1.postMessage({ab: ab, cb: ab}, [ab]);
|
||||||
|
ok(ab.byteLength == 0, "PostMessage - The size is: 0 == " + ab.byteLength)
|
||||||
} else {
|
} else {
|
||||||
ok(false, "Unknown message");
|
ok(false, "Unknown message");
|
||||||
}
|
}
|
||||||
|
@ -44,7 +45,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=677638
|
||||||
a.port1.addEventListener('message', receivePortMessage, false);
|
a.port1.addEventListener('message', receivePortMessage, false);
|
||||||
function receivePortMessage(evt) {
|
function receivePortMessage(evt) {
|
||||||
is(evt.data.ab.byteLength, size, "The size is: " + size + " == " + ab.byteLength);
|
is(evt.data.ab.byteLength, size, "The size is: " + size + " == " + ab.byteLength);
|
||||||
SimpleTest.finish();
|
window.removeEventListener('message', receiveMessage);
|
||||||
|
runTests();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start() is not implicity invoked when addEventListener is used.
|
// Start() is not implicity invoked when addEventListener is used.
|
||||||
|
@ -53,15 +55,57 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=677638
|
||||||
var size = 1024 * 1024 * 32;
|
var size = 1024 * 1024 * 32;
|
||||||
var ab = new ArrayBuffer(size);
|
var ab = new ArrayBuffer(size);
|
||||||
is(ab.byteLength, size, "The size is: " + size + " == " + ab.byteLength);
|
is(ab.byteLength, size, "The size is: " + size + " == " + ab.byteLength);
|
||||||
|
|
||||||
function runTest() {
|
|
||||||
a.port1.postMessage({ab: ab, cb: ab}, [ab]);
|
|
||||||
ok(ab.byteLength == 0, "PostMessage - The size is: 0 == " + ab.byteLength)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function port_test() {
|
||||||
|
window.addEventListener('message', receiveMessage, false);
|
||||||
|
function receiveMessage(evt) {
|
||||||
|
ok(evt.data.type == 'OK', evt.data.msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
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_transferable.html");
|
||||||
|
div.appendChild(ifr);
|
||||||
|
|
||||||
|
function iframeLoaded() {
|
||||||
|
ifr.contentWindow.postMessage('foobar!', '*', [a.port2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
a.port1.onmessage = function(evt) {
|
||||||
|
ok(evt.ports.length == 1, "Iframe sent a new port!");
|
||||||
|
evt.ports[0].onmessage = function(evt) {
|
||||||
|
is(evt.data, "hello world!", "Message sent and received!");
|
||||||
|
runTests();
|
||||||
|
}
|
||||||
|
|
||||||
|
evt.ports[0].postMessage("hello world!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var tests = [
|
||||||
|
basic_test,
|
||||||
|
port_test
|
||||||
|
];
|
||||||
|
|
||||||
|
function runTests() {
|
||||||
|
if (!tests.length) {
|
||||||
|
SimpleTest.finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var t = tests.shift();
|
||||||
|
t();
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleTest.waitForExplicitFinish();
|
SimpleTest.waitForExplicitFinish();
|
||||||
SpecialPowers.pushPrefEnv({"set": [["dom.messageChannel.enabled", true]]}, start);
|
SpecialPowers.pushPrefEnv({"set": [["dom.messageChannel.enabled", true]]}, runTests);
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -0,0 +1,60 @@
|
||||||
|
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<!--
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=677638
|
||||||
|
-->
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Test for Bug 677638 - 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=677638">Mozilla Bug 677638</a>
|
||||||
|
<p id="display"></p>
|
||||||
|
<div id="content" style="display: none">
|
||||||
|
<iframe name="x" id="x"></iframe>
|
||||||
|
<iframe name="y" id="y"></iframe>
|
||||||
|
</div>
|
||||||
|
<pre id="test">
|
||||||
|
</pre>
|
||||||
|
<script type="application/javascript">
|
||||||
|
|
||||||
|
var tests = [ 0, 3 ];
|
||||||
|
|
||||||
|
function runTests() {
|
||||||
|
if (!tests.length) {
|
||||||
|
SimpleTest.finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var a = new Worker('worker_messageChannel.js');
|
||||||
|
a.onmessage = function(evt) {
|
||||||
|
if (evt.data.type == 'finish') {
|
||||||
|
runTests();
|
||||||
|
} else if (evt.data.type == 'info') {
|
||||||
|
info(evt.data.message);
|
||||||
|
} else if (evt.data.type == 'check') {
|
||||||
|
ok(evt.data.check, evt.data.message);
|
||||||
|
} else if (evt.data.type == 'port') {
|
||||||
|
is(evt.ports.length, 1, "A port has been received!");
|
||||||
|
evt.ports[0].onmessage = function(e) {
|
||||||
|
e.target.postMessage(e.data);
|
||||||
|
}
|
||||||
|
} else if (evt.data.type == 'newport') {
|
||||||
|
var ch = new MessageChannel();
|
||||||
|
ok(ch, "MessageChannel created");
|
||||||
|
ch.port1.postMessage(42);
|
||||||
|
a.postMessage('a gift!', [ch.port2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a.postMessage(tests.shift());
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
SpecialPowers.pushPrefEnv({"set": [["dom.messageChannel.enabled", true]]}, runTests);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,119 @@
|
||||||
|
function ok(a, msg) {
|
||||||
|
postMessage({ type: 'check', check: !!a, message: msg });
|
||||||
|
}
|
||||||
|
|
||||||
|
function is(a, b, msg) {
|
||||||
|
ok (a === b, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
function info(msg) {
|
||||||
|
postMessage({ type: 'info', message: msg });
|
||||||
|
}
|
||||||
|
|
||||||
|
function finish() {
|
||||||
|
postMessage({ type: 'finish' });
|
||||||
|
}
|
||||||
|
|
||||||
|
function basic()
|
||||||
|
{
|
||||||
|
var a = new MessageChannel();
|
||||||
|
ok(a, "MessageChannel created");
|
||||||
|
|
||||||
|
var port1 = a.port1;
|
||||||
|
ok(port1, "MessageChannel.port1 exists");
|
||||||
|
is(port1, a.port1, "MessageChannel.port1 is port1");
|
||||||
|
|
||||||
|
var port2 = a.port2;
|
||||||
|
ok(port2, "MessageChannel.port1 exists");
|
||||||
|
is(port2, a.port2, "MessageChannel.port2 is port2");
|
||||||
|
|
||||||
|
[ 'postMessage', 'start', 'close' ].forEach(function(e) {
|
||||||
|
ok(e in port1, "MessagePort1." + e + " exists");
|
||||||
|
ok(e in port2, "MessagePort2." + e + " exists");
|
||||||
|
});
|
||||||
|
|
||||||
|
runTests();
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendMessages()
|
||||||
|
{
|
||||||
|
var a = new MessageChannel();
|
||||||
|
ok(a, "MessageChannel created");
|
||||||
|
|
||||||
|
a.port1.postMessage("Hello world!");
|
||||||
|
a.port1.onmessage = function(e) {
|
||||||
|
is(e.data, "Hello world!", "The message is back!");
|
||||||
|
runTests();
|
||||||
|
}
|
||||||
|
|
||||||
|
a.port2.onmessage = function(e) {
|
||||||
|
a.port2.postMessage(e.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function transferPort()
|
||||||
|
{
|
||||||
|
var a = new MessageChannel();
|
||||||
|
ok(a, "MessageChannel created");
|
||||||
|
|
||||||
|
a.port1.postMessage("Hello world!");
|
||||||
|
a.port1.onmessage = function(e) {
|
||||||
|
is(e.data, "Hello world!", "The message is back!");
|
||||||
|
runTests();
|
||||||
|
}
|
||||||
|
|
||||||
|
postMessage({ type: 'port' }, [a.port2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function transferPort2()
|
||||||
|
{
|
||||||
|
onmessage = function(evt) {
|
||||||
|
is(evt.ports.length, 1, "A port has been received by the worker");
|
||||||
|
evt.ports[0].onmessage = function(e) {
|
||||||
|
is(e.data, 42, "Data is 42!");
|
||||||
|
runTests();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
postMessage({ type: 'newport' });
|
||||||
|
}
|
||||||
|
|
||||||
|
var tests = [
|
||||||
|
basic,
|
||||||
|
sendMessages,
|
||||||
|
transferPort,
|
||||||
|
transferPort2,
|
||||||
|
];
|
||||||
|
|
||||||
|
function runTests() {
|
||||||
|
if (!tests.length) {
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var t = tests.shift();
|
||||||
|
t();
|
||||||
|
}
|
||||||
|
|
||||||
|
var subworker;
|
||||||
|
onmessage = function(evt) {
|
||||||
|
if (evt.data == 0) {
|
||||||
|
runTests();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!subworker) {
|
||||||
|
info("Create a subworkers. ID: " + evt.data);
|
||||||
|
subworker = new Worker('worker_messageChannel.js');
|
||||||
|
subworker.onmessage = function(e) {
|
||||||
|
info("Proxy a message to the parent.");
|
||||||
|
postMessage(e.data, e.ports);
|
||||||
|
}
|
||||||
|
|
||||||
|
subworker.postMessage(evt.data - 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
info("Dispatch a message to the subworker.");
|
||||||
|
subworker.postMessage(evt.data, evt.ports);
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
onmessage = function(evt) {
|
||||||
|
evt.data.onmessage = function(event) {
|
||||||
|
evt.data.postMessage(event.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
postMessage("READY");
|
|
@ -96,6 +96,7 @@ DIRS += [
|
||||||
'camera',
|
'camera',
|
||||||
'audiochannel',
|
'audiochannel',
|
||||||
'broadcastchannel',
|
'broadcastchannel',
|
||||||
|
'messagechannel',
|
||||||
'promise',
|
'promise',
|
||||||
'smil',
|
'smil',
|
||||||
'telephony',
|
'telephony',
|
||||||
|
|
|
@ -7,7 +7,8 @@
|
||||||
* http://www.whatwg.org/specs/web-apps/current-work/#channel-messaging
|
* http://www.whatwg.org/specs/web-apps/current-work/#channel-messaging
|
||||||
*/
|
*/
|
||||||
|
|
||||||
[Constructor, Func="MessageChannel::Enabled"]
|
[Constructor, Func="MessageChannel::Enabled",
|
||||||
|
Exposed=(Window,Worker)]
|
||||||
interface MessageChannel {
|
interface MessageChannel {
|
||||||
readonly attribute MessagePort port1;
|
readonly attribute MessagePort port1;
|
||||||
readonly attribute MessagePort port2;
|
readonly attribute MessagePort port2;
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
using mozilla::dom::EventHandlerNonNull;
|
using mozilla::dom::EventHandlerNonNull;
|
||||||
using mozilla::dom::MessagePortBase;
|
using mozilla::dom::MessagePortBase;
|
||||||
|
using mozilla::dom::MessagePortIdentifier;
|
||||||
using mozilla::dom::Optional;
|
using mozilla::dom::Optional;
|
||||||
using mozilla::dom::Sequence;
|
using mozilla::dom::Sequence;
|
||||||
using mozilla::dom::AutoNoJSAPI;
|
using mozilla::dom::AutoNoJSAPI;
|
||||||
|
@ -96,7 +97,7 @@ MessagePort::~MessagePort()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MessagePort::PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
MessagePort::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||||
ErrorResult& aRv)
|
ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
|
@ -198,11 +199,11 @@ MessagePort::SetOnmessage(EventHandlerNonNull* aCallback)
|
||||||
Start();
|
Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<MessagePortBase>
|
bool
|
||||||
MessagePort::Clone()
|
MessagePort::CloneAndDisentangle(MessagePortIdentifier& aIdentifier)
|
||||||
{
|
{
|
||||||
NS_WARNING("Haven't implemented structured clone for these ports yet!");
|
NS_WARNING("Haven't implemented structured clone for these ports yet!");
|
||||||
return nullptr;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -43,7 +43,7 @@ public:
|
||||||
PrefEnabled();
|
PrefEnabled();
|
||||||
|
|
||||||
virtual void
|
virtual void
|
||||||
PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||||
ErrorResult& aRv) override;
|
ErrorResult& aRv) override;
|
||||||
|
|
||||||
|
@ -71,8 +71,8 @@ public:
|
||||||
virtual void
|
virtual void
|
||||||
SetOnmessage(EventHandlerNonNull* aCallback) override;
|
SetOnmessage(EventHandlerNonNull* aCallback) override;
|
||||||
|
|
||||||
virtual already_AddRefed<MessagePortBase>
|
virtual bool
|
||||||
Clone() override;
|
CloneAndDisentangle(MessagePortIdentifier& aIdentifier) override;
|
||||||
|
|
||||||
bool
|
bool
|
||||||
IsClosed() const
|
IsClosed() const
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "nsGlobalWindow.h"
|
#include "nsGlobalWindow.h"
|
||||||
#include "nsIDocument.h"
|
#include "nsIDocument.h"
|
||||||
#include "WorkerPrivate.h"
|
#include "WorkerPrivate.h"
|
||||||
|
#include "WorkerStructuredClone.h"
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
using namespace mozilla::dom;
|
using namespace mozilla::dom;
|
||||||
|
@ -75,16 +76,18 @@ class ServiceWorkerClientPostMessageRunnable final : public nsRunnable
|
||||||
{
|
{
|
||||||
uint64_t mWindowId;
|
uint64_t mWindowId;
|
||||||
JSAutoStructuredCloneBuffer mBuffer;
|
JSAutoStructuredCloneBuffer mBuffer;
|
||||||
nsTArray<nsCOMPtr<nsISupports>> mClonedObjects;
|
WorkerStructuredCloneClosure mClosure;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ServiceWorkerClientPostMessageRunnable(uint64_t aWindowId,
|
ServiceWorkerClientPostMessageRunnable(uint64_t aWindowId,
|
||||||
JSAutoStructuredCloneBuffer&& aData,
|
JSAutoStructuredCloneBuffer&& aData,
|
||||||
nsTArray<nsCOMPtr<nsISupports>>& aClonedObjects)
|
WorkerStructuredCloneClosure& aClosure)
|
||||||
: mWindowId(aWindowId),
|
: mWindowId(aWindowId),
|
||||||
mBuffer(Move(aData))
|
mBuffer(Move(aData))
|
||||||
{
|
{
|
||||||
mClonedObjects.SwapElements(aClonedObjects);
|
mClosure.mClonedObjects.SwapElements(aClosure.mClonedObjects);
|
||||||
|
MOZ_ASSERT(aClosure.mMessagePorts.IsEmpty());
|
||||||
|
mClosure.mMessagePortIdentifiers.SwapElements(aClosure.mMessagePortIdentifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHOD
|
NS_IMETHOD
|
||||||
|
@ -118,8 +121,10 @@ private:
|
||||||
|
|
||||||
// Release reference to objects that were AddRef'd for
|
// Release reference to objects that were AddRef'd for
|
||||||
// cloning into worker when array goes out of scope.
|
// cloning into worker when array goes out of scope.
|
||||||
nsTArray<nsCOMPtr<nsISupports>> clonedObjects;
|
WorkerStructuredCloneClosure closure;
|
||||||
clonedObjects.SwapElements(mClonedObjects);
|
closure.mClonedObjects.SwapElements(mClosure.mClonedObjects);
|
||||||
|
MOZ_ASSERT(mClosure.mMessagePorts.IsEmpty());
|
||||||
|
closure.mMessagePortIdentifiers.SwapElements(mClosure.mMessagePortIdentifiers);
|
||||||
|
|
||||||
JS::Rooted<JS::Value> messageData(aCx);
|
JS::Rooted<JS::Value> messageData(aCx);
|
||||||
if (!mBuffer.read(aCx, &messageData,
|
if (!mBuffer.read(aCx, &messageData,
|
||||||
|
@ -185,16 +190,17 @@ ServiceWorkerClient::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||||
|
|
||||||
const JSStructuredCloneCallbacks* callbacks = WorkerStructuredCloneCallbacks(false);
|
const JSStructuredCloneCallbacks* callbacks = WorkerStructuredCloneCallbacks(false);
|
||||||
|
|
||||||
nsTArray<nsCOMPtr<nsISupports>> clonedObjects;
|
WorkerStructuredCloneClosure closure;
|
||||||
|
|
||||||
JSAutoStructuredCloneBuffer buffer;
|
JSAutoStructuredCloneBuffer buffer;
|
||||||
if (!buffer.write(aCx, aMessage, transferable, callbacks, &clonedObjects)) {
|
if (!buffer.write(aCx, aMessage, transferable, callbacks, &closure)) {
|
||||||
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
|
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsRefPtr<ServiceWorkerClientPostMessageRunnable> runnable =
|
nsRefPtr<ServiceWorkerClientPostMessageRunnable> runnable =
|
||||||
new ServiceWorkerClientPostMessageRunnable(mWindowId, Move(buffer), clonedObjects);
|
new ServiceWorkerClientPostMessageRunnable(mWindowId, Move(buffer),
|
||||||
|
closure);
|
||||||
nsresult rv = NS_DispatchToMainThread(runnable);
|
nsresult rv = NS_DispatchToMainThread(runnable);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
aRv.Throw(NS_ERROR_FAILURE);
|
aRv.Throw(NS_ERROR_FAILURE);
|
||||||
|
|
|
@ -52,6 +52,8 @@
|
||||||
#include "mozilla/dom/ImageDataBinding.h"
|
#include "mozilla/dom/ImageDataBinding.h"
|
||||||
#include "mozilla/dom/MessageEvent.h"
|
#include "mozilla/dom/MessageEvent.h"
|
||||||
#include "mozilla/dom/MessageEventBinding.h"
|
#include "mozilla/dom/MessageEventBinding.h"
|
||||||
|
#include "mozilla/dom/MessagePort.h"
|
||||||
|
#include "mozilla/dom/MessagePortBinding.h"
|
||||||
#include "mozilla/dom/MessagePortList.h"
|
#include "mozilla/dom/MessagePortList.h"
|
||||||
#include "mozilla/dom/Promise.h"
|
#include "mozilla/dom/Promise.h"
|
||||||
#include "mozilla/dom/PromiseDebugging.h"
|
#include "mozilla/dom/PromiseDebugging.h"
|
||||||
|
@ -105,6 +107,7 @@
|
||||||
#include "WorkerFeature.h"
|
#include "WorkerFeature.h"
|
||||||
#include "WorkerRunnable.h"
|
#include "WorkerRunnable.h"
|
||||||
#include "WorkerScope.h"
|
#include "WorkerScope.h"
|
||||||
|
#include "WorkerStructuredClone.h"
|
||||||
#include "WorkerThread.h"
|
#include "WorkerThread.h"
|
||||||
|
|
||||||
#ifdef XP_WIN
|
#ifdef XP_WIN
|
||||||
|
@ -511,7 +514,7 @@ bool
|
||||||
WriteBlobOrFile(JSContext* aCx,
|
WriteBlobOrFile(JSContext* aCx,
|
||||||
JSStructuredCloneWriter* aWriter,
|
JSStructuredCloneWriter* aWriter,
|
||||||
BlobImpl* aBlobOrBlobImpl,
|
BlobImpl* aBlobOrBlobImpl,
|
||||||
nsTArray<nsCOMPtr<nsISupports>>& aClonedObjects)
|
WorkerStructuredCloneClosure& aClosure)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aCx);
|
MOZ_ASSERT(aCx);
|
||||||
MOZ_ASSERT(aWriter);
|
MOZ_ASSERT(aWriter);
|
||||||
|
@ -529,7 +532,7 @@ WriteBlobOrFile(JSContext* aCx,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
aClonedObjects.AppendElement(aBlobOrBlobImpl);
|
aClosure.mClonedObjects.AppendElement(aBlobOrBlobImpl);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -547,7 +550,7 @@ bool
|
||||||
WriteFormData(JSContext* aCx,
|
WriteFormData(JSContext* aCx,
|
||||||
JSStructuredCloneWriter* aWriter,
|
JSStructuredCloneWriter* aWriter,
|
||||||
nsFormData* aFormData,
|
nsFormData* aFormData,
|
||||||
nsTArray<nsCOMPtr<nsISupports>>& aClonedObjects)
|
WorkerStructuredCloneClosure& aClosure)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aCx);
|
MOZ_ASSERT(aCx);
|
||||||
MOZ_ASSERT(aWriter);
|
MOZ_ASSERT(aWriter);
|
||||||
|
@ -560,11 +563,11 @@ WriteFormData(JSContext* aCx,
|
||||||
class MOZ_STACK_CLASS Closure {
|
class MOZ_STACK_CLASS Closure {
|
||||||
JSContext* mCx;
|
JSContext* mCx;
|
||||||
JSStructuredCloneWriter* mWriter;
|
JSStructuredCloneWriter* mWriter;
|
||||||
nsTArray<nsCOMPtr<nsISupports>>& mClones;
|
WorkerStructuredCloneClosure& mClones;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Closure(JSContext* aCx, JSStructuredCloneWriter* aWriter,
|
Closure(JSContext* aCx, JSStructuredCloneWriter* aWriter,
|
||||||
nsTArray<nsCOMPtr<nsISupports>>& aClones)
|
WorkerStructuredCloneClosure& aClones)
|
||||||
: mCx(aCx), mWriter(aWriter), mClones(aClones)
|
: mCx(aCx), mWriter(aWriter), mClones(aClones)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
@ -595,7 +598,7 @@ WriteFormData(JSContext* aCx,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Closure closure(aCx, aWriter, aClonedObjects);
|
Closure closure(aCx, aWriter, aClosure);
|
||||||
return aFormData->ForEach(Closure::Write, &closure);
|
return aFormData->ForEach(Closure::Write, &closure);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -639,9 +642,7 @@ struct WorkerStructuredCloneCallbacks
|
||||||
{
|
{
|
||||||
NS_ASSERTION(aClosure, "Null pointer!");
|
NS_ASSERTION(aClosure, "Null pointer!");
|
||||||
|
|
||||||
// We'll stash any nsISupports pointers that need to be AddRef'd here.
|
auto* closure = static_cast<WorkerStructuredCloneClosure*>(aClosure);
|
||||||
auto* clonedObjects =
|
|
||||||
static_cast<nsTArray<nsCOMPtr<nsISupports>>*>(aClosure);
|
|
||||||
|
|
||||||
// See if this is a Blob/File object.
|
// See if this is a Blob/File object.
|
||||||
{
|
{
|
||||||
|
@ -650,7 +651,7 @@ struct WorkerStructuredCloneCallbacks
|
||||||
BlobImpl* blobImpl = blob->Impl();
|
BlobImpl* blobImpl = blob->Impl();
|
||||||
MOZ_ASSERT(blobImpl);
|
MOZ_ASSERT(blobImpl);
|
||||||
|
|
||||||
if (WriteBlobOrFile(aCx, aWriter, blobImpl, *clonedObjects)) {
|
if (WriteBlobOrFile(aCx, aWriter, blobImpl, *closure)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -668,7 +669,7 @@ struct WorkerStructuredCloneCallbacks
|
||||||
{
|
{
|
||||||
nsFormData* formData = nullptr;
|
nsFormData* formData = nullptr;
|
||||||
if (NS_SUCCEEDED(UNWRAP_OBJECT(FormData, aObj, formData))) {
|
if (NS_SUCCEEDED(UNWRAP_OBJECT(FormData, aObj, formData))) {
|
||||||
if (WriteFormData(aCx, aWriter, formData, *clonedObjects)) {
|
if (WriteFormData(aCx, aWriter, formData, *closure)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -683,15 +684,96 @@ struct WorkerStructuredCloneCallbacks
|
||||||
{
|
{
|
||||||
Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
|
Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
ReadTransfer(JSContext* aCx, JSStructuredCloneReader* aReader,
|
||||||
|
uint32_t aTag, void* aContent, uint64_t aExtraData,
|
||||||
|
void* aClosure, JS::MutableHandle<JSObject*> aReturnObject)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aClosure);
|
||||||
|
|
||||||
|
auto* closure = static_cast<WorkerStructuredCloneClosure*>(aClosure);
|
||||||
|
|
||||||
|
if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) {
|
||||||
|
MOZ_ASSERT(!aContent);
|
||||||
|
MOZ_ASSERT(aExtraData < closure->mMessagePortIdentifiers.Length());
|
||||||
|
|
||||||
|
ErrorResult rv;
|
||||||
|
nsRefPtr<MessagePortBase> port =
|
||||||
|
dom::MessagePort::Create(closure->mParentWindow,
|
||||||
|
closure->mMessagePortIdentifiers[aExtraData],
|
||||||
|
rv);
|
||||||
|
|
||||||
|
if (NS_WARN_IF(rv.Failed())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
closure->mMessagePorts.AppendElement(port);
|
||||||
|
|
||||||
|
JS::Rooted<JS::Value> value(aCx);
|
||||||
|
if (!GetOrCreateDOMReflector(aCx, port, &value)) {
|
||||||
|
JS_ClearPendingException(aCx);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
aReturnObject.set(&value.toObject());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
Transfer(JSContext* aCx, JS::Handle<JSObject*> aObj, void* aClosure,
|
||||||
|
uint32_t* aTag, JS::TransferableOwnership* aOwnership,
|
||||||
|
void** aContent, uint64_t *aExtraData)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aClosure);
|
||||||
|
|
||||||
|
auto* closure = static_cast<WorkerStructuredCloneClosure*>(aClosure);
|
||||||
|
|
||||||
|
MessagePortBase* port;
|
||||||
|
nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port);
|
||||||
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
if (NS_WARN_IF(closure->mTransferredPorts.Contains(port))) {
|
||||||
|
// No duplicates.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MessagePortIdentifier identifier;
|
||||||
|
if (!port->CloneAndDisentangle(identifier)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
closure->mMessagePortIdentifiers.AppendElement(identifier);
|
||||||
|
closure->mTransferredPorts.AppendElement(port);
|
||||||
|
|
||||||
|
*aTag = SCTAG_DOM_MAP_MESSAGEPORT;
|
||||||
|
*aOwnership = JS::SCTAG_TMO_CUSTOM;
|
||||||
|
*aContent = nullptr;
|
||||||
|
*aExtraData = closure->mMessagePortIdentifiers.Length() - 1;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
FreeTransfer(uint32_t aTag, JS::TransferableOwnership aOwnership,
|
||||||
|
void *aContent, uint64_t aExtraData, void* aClosure)
|
||||||
|
{
|
||||||
|
// Nothing to do.
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const JSStructuredCloneCallbacks gWorkerStructuredCloneCallbacks = {
|
const JSStructuredCloneCallbacks gWorkerStructuredCloneCallbacks = {
|
||||||
WorkerStructuredCloneCallbacks::Read,
|
WorkerStructuredCloneCallbacks::Read,
|
||||||
WorkerStructuredCloneCallbacks::Write,
|
WorkerStructuredCloneCallbacks::Write,
|
||||||
WorkerStructuredCloneCallbacks::Error,
|
WorkerStructuredCloneCallbacks::Error,
|
||||||
nullptr,
|
WorkerStructuredCloneCallbacks::ReadTransfer,
|
||||||
nullptr,
|
WorkerStructuredCloneCallbacks::Transfer,
|
||||||
nullptr
|
WorkerStructuredCloneCallbacks::FreeTransfer
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MainThreadWorkerStructuredCloneCallbacks
|
struct MainThreadWorkerStructuredCloneCallbacks
|
||||||
|
@ -731,9 +813,7 @@ struct MainThreadWorkerStructuredCloneCallbacks
|
||||||
|
|
||||||
NS_ASSERTION(aClosure, "Null pointer!");
|
NS_ASSERTION(aClosure, "Null pointer!");
|
||||||
|
|
||||||
// We'll stash any nsISupports pointers that need to be AddRef'd here.
|
auto* closure = static_cast<WorkerStructuredCloneClosure*>(aClosure);
|
||||||
auto* clonedObjects =
|
|
||||||
static_cast<nsTArray<nsCOMPtr<nsISupports>>*>(aClosure);
|
|
||||||
|
|
||||||
// See if this is a Blob/File object.
|
// See if this is a Blob/File object.
|
||||||
{
|
{
|
||||||
|
@ -744,7 +824,7 @@ struct MainThreadWorkerStructuredCloneCallbacks
|
||||||
|
|
||||||
if (!blobImpl->MayBeClonedToOtherThreads()) {
|
if (!blobImpl->MayBeClonedToOtherThreads()) {
|
||||||
NS_WARNING("Not all the blob implementations can be sent between threads.");
|
NS_WARNING("Not all the blob implementations can be sent between threads.");
|
||||||
} else if (WriteBlobOrFile(aCx, aWriter, blobImpl, *clonedObjects)) {
|
} else if (WriteBlobOrFile(aCx, aWriter, blobImpl, *closure)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -767,9 +847,9 @@ const JSStructuredCloneCallbacks gMainThreadWorkerStructuredCloneCallbacks = {
|
||||||
MainThreadWorkerStructuredCloneCallbacks::Read,
|
MainThreadWorkerStructuredCloneCallbacks::Read,
|
||||||
MainThreadWorkerStructuredCloneCallbacks::Write,
|
MainThreadWorkerStructuredCloneCallbacks::Write,
|
||||||
MainThreadWorkerStructuredCloneCallbacks::Error,
|
MainThreadWorkerStructuredCloneCallbacks::Error,
|
||||||
nullptr,
|
WorkerStructuredCloneCallbacks::ReadTransfer,
|
||||||
nullptr,
|
WorkerStructuredCloneCallbacks::Transfer,
|
||||||
nullptr
|
WorkerStructuredCloneCallbacks::FreeTransfer
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ChromeWorkerStructuredCloneCallbacks
|
struct ChromeWorkerStructuredCloneCallbacks
|
||||||
|
@ -800,9 +880,9 @@ const JSStructuredCloneCallbacks gChromeWorkerStructuredCloneCallbacks = {
|
||||||
ChromeWorkerStructuredCloneCallbacks::Read,
|
ChromeWorkerStructuredCloneCallbacks::Read,
|
||||||
ChromeWorkerStructuredCloneCallbacks::Write,
|
ChromeWorkerStructuredCloneCallbacks::Write,
|
||||||
ChromeWorkerStructuredCloneCallbacks::Error,
|
ChromeWorkerStructuredCloneCallbacks::Error,
|
||||||
nullptr,
|
WorkerStructuredCloneCallbacks::ReadTransfer,
|
||||||
nullptr,
|
WorkerStructuredCloneCallbacks::Transfer,
|
||||||
nullptr
|
WorkerStructuredCloneCallbacks::FreeTransfer
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MainThreadChromeWorkerStructuredCloneCallbacks
|
struct MainThreadChromeWorkerStructuredCloneCallbacks
|
||||||
|
@ -1153,7 +1233,7 @@ private:
|
||||||
class MessageEventRunnable final : public WorkerRunnable
|
class MessageEventRunnable final : public WorkerRunnable
|
||||||
{
|
{
|
||||||
JSAutoStructuredCloneBuffer mBuffer;
|
JSAutoStructuredCloneBuffer mBuffer;
|
||||||
nsTArray<nsCOMPtr<nsISupports> > mClonedObjects;
|
WorkerStructuredCloneClosure mClosure;
|
||||||
uint64_t mMessagePortSerial;
|
uint64_t mMessagePortSerial;
|
||||||
bool mToMessagePort;
|
bool mToMessagePort;
|
||||||
|
|
||||||
|
@ -1163,15 +1243,24 @@ class MessageEventRunnable final : public WorkerRunnable
|
||||||
public:
|
public:
|
||||||
MessageEventRunnable(WorkerPrivate* aWorkerPrivate,
|
MessageEventRunnable(WorkerPrivate* aWorkerPrivate,
|
||||||
TargetAndBusyBehavior aBehavior,
|
TargetAndBusyBehavior aBehavior,
|
||||||
JSAutoStructuredCloneBuffer&& aData,
|
|
||||||
nsTArray<nsCOMPtr<nsISupports> >& aClonedObjects,
|
|
||||||
bool aToMessagePort, uint64_t aMessagePortSerial)
|
bool aToMessagePort, uint64_t aMessagePortSerial)
|
||||||
: WorkerRunnable(aWorkerPrivate, aBehavior)
|
: WorkerRunnable(aWorkerPrivate, aBehavior)
|
||||||
, mBuffer(Move(aData))
|
|
||||||
, mMessagePortSerial(aMessagePortSerial)
|
, mMessagePortSerial(aMessagePortSerial)
|
||||||
, mToMessagePort(aToMessagePort)
|
, mToMessagePort(aToMessagePort)
|
||||||
{
|
{
|
||||||
mClonedObjects.SwapElements(aClonedObjects);
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Write(JSContext* aCx, JS::Handle<JS::Value> aValue,
|
||||||
|
JS::Handle<JS::Value> aTransferredValue,
|
||||||
|
const JSStructuredCloneCallbacks *aCallbacks)
|
||||||
|
{
|
||||||
|
bool ok = mBuffer.write(aCx, aValue, aTransferredValue, aCallbacks,
|
||||||
|
&mClosure);
|
||||||
|
// This hashtable has to be empty because it could contain MessagePort
|
||||||
|
// objects that cannot be freed on a different thread.
|
||||||
|
mClosure.mTransferredPorts.Clear();
|
||||||
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1186,12 +1275,19 @@ public:
|
||||||
{
|
{
|
||||||
// Release reference to objects that were AddRef'd for
|
// Release reference to objects that were AddRef'd for
|
||||||
// cloning into worker when array goes out of scope.
|
// cloning into worker when array goes out of scope.
|
||||||
nsTArray<nsCOMPtr<nsISupports>> clonedObjects;
|
WorkerStructuredCloneClosure closure;
|
||||||
clonedObjects.SwapElements(mClonedObjects);
|
closure.mClonedObjects.SwapElements(mClosure.mClonedObjects);
|
||||||
|
MOZ_ASSERT(mClosure.mMessagePorts.IsEmpty());
|
||||||
|
closure.mMessagePortIdentifiers.SwapElements(mClosure.mMessagePortIdentifiers);
|
||||||
|
|
||||||
|
if (aIsMainThread) {
|
||||||
|
closure.mParentWindow = do_QueryInterface(aTarget->GetParentObject());
|
||||||
|
}
|
||||||
|
|
||||||
JS::Rooted<JS::Value> messageData(aCx);
|
JS::Rooted<JS::Value> messageData(aCx);
|
||||||
if (!mBuffer.read(aCx, &messageData,
|
if (!mBuffer.read(aCx, &messageData,
|
||||||
workers::WorkerStructuredCloneCallbacks(aIsMainThread))) {
|
workers::WorkerStructuredCloneCallbacks(aIsMainThread),
|
||||||
|
&closure)) {
|
||||||
xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
|
xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1217,7 +1313,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
event->SetTrusted(true);
|
event->SetTrusted(true);
|
||||||
|
event->SetPorts(new MessagePortList(static_cast<dom::Event*>(event.get()),
|
||||||
|
closure.mMessagePorts));
|
||||||
nsCOMPtr<nsIDOMEvent> domEvent = do_QueryObject(event);
|
nsCOMPtr<nsIDOMEvent> domEvent = do_QueryObject(event);
|
||||||
|
|
||||||
nsEventStatus dummy = nsEventStatus_eIgnore;
|
nsEventStatus dummy = nsEventStatus_eIgnore;
|
||||||
|
@ -1243,7 +1340,7 @@ private:
|
||||||
aWorkerPrivate->DispatchMessageEventToMessagePort(aCx,
|
aWorkerPrivate->DispatchMessageEventToMessagePort(aCx,
|
||||||
mMessagePortSerial,
|
mMessagePortSerial,
|
||||||
Move(mBuffer),
|
Move(mBuffer),
|
||||||
mClonedObjects);
|
mClosure);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aWorkerPrivate->IsFrozen()) {
|
if (aWorkerPrivate->IsFrozen()) {
|
||||||
|
@ -3379,19 +3476,16 @@ WorkerPrivateParent<Derived>::PostMessageInternal(
|
||||||
transferable.setObject(*array);
|
transferable.setObject(*array);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsTArray<nsCOMPtr<nsISupports>> clonedObjects;
|
nsRefPtr<MessageEventRunnable> runnable =
|
||||||
|
new MessageEventRunnable(ParentAsWorkerPrivate(),
|
||||||
|
WorkerRunnable::WorkerThreadModifyBusyCount,
|
||||||
|
aToMessagePort, aMessagePortSerial);
|
||||||
|
|
||||||
JSAutoStructuredCloneBuffer buffer;
|
if (!runnable->Write(aCx, aMessage, transferable, callbacks)) {
|
||||||
if (!buffer.write(aCx, aMessage, transferable, callbacks, &clonedObjects)) {
|
|
||||||
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
|
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsRefPtr<MessageEventRunnable> runnable =
|
|
||||||
new MessageEventRunnable(ParentAsWorkerPrivate(),
|
|
||||||
WorkerRunnable::WorkerThreadModifyBusyCount,
|
|
||||||
Move(buffer), clonedObjects, aToMessagePort,
|
|
||||||
aMessagePortSerial);
|
|
||||||
runnable->SetMessageSource(aClientInfo);
|
runnable->SetMessageSource(aClientInfo);
|
||||||
|
|
||||||
if (!runnable->Dispatch(aCx)) {
|
if (!runnable->Dispatch(aCx)) {
|
||||||
|
@ -3432,14 +3526,16 @@ bool
|
||||||
WorkerPrivateParent<Derived>::DispatchMessageEventToMessagePort(
|
WorkerPrivateParent<Derived>::DispatchMessageEventToMessagePort(
|
||||||
JSContext* aCx, uint64_t aMessagePortSerial,
|
JSContext* aCx, uint64_t aMessagePortSerial,
|
||||||
JSAutoStructuredCloneBuffer&& aBuffer,
|
JSAutoStructuredCloneBuffer&& aBuffer,
|
||||||
nsTArray<nsCOMPtr<nsISupports>>& aClonedObjects)
|
WorkerStructuredCloneClosure& aClosure)
|
||||||
{
|
{
|
||||||
AssertIsOnMainThread();
|
AssertIsOnMainThread();
|
||||||
|
|
||||||
JSAutoStructuredCloneBuffer buffer(Move(aBuffer));
|
JSAutoStructuredCloneBuffer buffer(Move(aBuffer));
|
||||||
|
|
||||||
nsTArray<nsCOMPtr<nsISupports>> clonedObjects;
|
WorkerStructuredCloneClosure closure;
|
||||||
clonedObjects.SwapElements(aClonedObjects);
|
closure.mClonedObjects.SwapElements(aClosure.mClonedObjects);
|
||||||
|
MOZ_ASSERT(aClosure.mMessagePorts.IsEmpty());
|
||||||
|
closure.mMessagePortIdentifiers.SwapElements(aClosure.mMessagePortIdentifiers);
|
||||||
|
|
||||||
SharedWorker* sharedWorker;
|
SharedWorker* sharedWorker;
|
||||||
if (!mSharedWorkers.Get(aMessagePortSerial, &sharedWorker)) {
|
if (!mSharedWorkers.Get(aMessagePortSerial, &sharedWorker)) {
|
||||||
|
@ -3454,6 +3550,8 @@ WorkerPrivateParent<Derived>::DispatchMessageEventToMessagePort(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
closure.mParentWindow = do_QueryInterface(port->GetParentObject());
|
||||||
|
|
||||||
AutoJSAPI jsapi;
|
AutoJSAPI jsapi;
|
||||||
if (NS_WARN_IF(!jsapi.InitWithLegacyErrorReporting(port->GetParentObject()))) {
|
if (NS_WARN_IF(!jsapi.InitWithLegacyErrorReporting(port->GetParentObject()))) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -3461,7 +3559,8 @@ WorkerPrivateParent<Derived>::DispatchMessageEventToMessagePort(
|
||||||
JSContext* cx = jsapi.cx();
|
JSContext* cx = jsapi.cx();
|
||||||
|
|
||||||
JS::Rooted<JS::Value> data(cx);
|
JS::Rooted<JS::Value> data(cx);
|
||||||
if (!buffer.read(cx, &data, WorkerStructuredCloneCallbacks(true))) {
|
if (!buffer.read(cx, &data, WorkerStructuredCloneCallbacks(true),
|
||||||
|
&closure)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3478,11 +3577,7 @@ WorkerPrivateParent<Derived>::DispatchMessageEventToMessagePort(
|
||||||
|
|
||||||
event->SetTrusted(true);
|
event->SetTrusted(true);
|
||||||
|
|
||||||
nsTArray<nsRefPtr<MessagePortBase>> ports;
|
event->SetPorts(new MessagePortList(port, closure.mMessagePorts));
|
||||||
ports.AppendElement(port);
|
|
||||||
|
|
||||||
nsRefPtr<MessagePortList> portList = new MessagePortList(port, ports);
|
|
||||||
event->SetPorts(portList);
|
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMEvent> domEvent;
|
nsCOMPtr<nsIDOMEvent> domEvent;
|
||||||
CallQueryInterface(event.get(), getter_AddRefs(domEvent));
|
CallQueryInterface(event.get(), getter_AddRefs(domEvent));
|
||||||
|
@ -6182,19 +6277,16 @@ WorkerPrivate::PostMessageToParentInternal(
|
||||||
&gChromeWorkerStructuredCloneCallbacks :
|
&gChromeWorkerStructuredCloneCallbacks :
|
||||||
&gWorkerStructuredCloneCallbacks;
|
&gWorkerStructuredCloneCallbacks;
|
||||||
|
|
||||||
nsTArray<nsCOMPtr<nsISupports>> clonedObjects;
|
nsRefPtr<MessageEventRunnable> runnable =
|
||||||
|
new MessageEventRunnable(this,
|
||||||
|
WorkerRunnable::ParentThreadUnchangedBusyCount,
|
||||||
|
aToMessagePort, aMessagePortSerial);
|
||||||
|
|
||||||
JSAutoStructuredCloneBuffer buffer;
|
if (!runnable->Write(aCx, aMessage, transferable, callbacks)) {
|
||||||
if (!buffer.write(aCx, aMessage, transferable, callbacks, &clonedObjects)) {
|
|
||||||
aRv = NS_ERROR_DOM_DATA_CLONE_ERR;
|
aRv = NS_ERROR_DOM_DATA_CLONE_ERR;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsRefPtr<MessageEventRunnable> runnable =
|
|
||||||
new MessageEventRunnable(this,
|
|
||||||
WorkerRunnable::ParentThreadUnchangedBusyCount,
|
|
||||||
Move(buffer), clonedObjects, aToMessagePort,
|
|
||||||
aMessagePortSerial);
|
|
||||||
if (!runnable->Dispatch(aCx)) {
|
if (!runnable->Dispatch(aCx)) {
|
||||||
aRv = NS_ERROR_FAILURE;
|
aRv = NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
@ -7348,4 +7440,20 @@ ChromeWorkerStructuredCloneCallbacks(bool aMainRuntime)
|
||||||
// Force instantiation.
|
// Force instantiation.
|
||||||
template class WorkerPrivateParent<WorkerPrivate>;
|
template class WorkerPrivateParent<WorkerPrivate>;
|
||||||
|
|
||||||
|
WorkerStructuredCloneClosure::WorkerStructuredCloneClosure()
|
||||||
|
{}
|
||||||
|
|
||||||
|
WorkerStructuredCloneClosure::~WorkerStructuredCloneClosure()
|
||||||
|
{}
|
||||||
|
|
||||||
|
void
|
||||||
|
WorkerStructuredCloneClosure::Clear()
|
||||||
|
{
|
||||||
|
mParentWindow = nullptr;
|
||||||
|
mClonedObjects.Clear();
|
||||||
|
mMessagePorts.Clear();
|
||||||
|
mMessagePortIdentifiers.Clear();
|
||||||
|
mTransferredPorts.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
END_WORKERS_NAMESPACE
|
END_WORKERS_NAMESPACE
|
||||||
|
|
|
@ -73,6 +73,7 @@ class WorkerDebuggerGlobalScope;
|
||||||
class WorkerGlobalScope;
|
class WorkerGlobalScope;
|
||||||
class WorkerPrivate;
|
class WorkerPrivate;
|
||||||
class WorkerRunnable;
|
class WorkerRunnable;
|
||||||
|
class WorkerStructuredCloneClosure;
|
||||||
class WorkerThread;
|
class WorkerThread;
|
||||||
|
|
||||||
// SharedMutex is a small wrapper around an (internal) reference-counted Mutex
|
// SharedMutex is a small wrapper around an (internal) reference-counted Mutex
|
||||||
|
@ -349,7 +350,7 @@ public:
|
||||||
JSContext* aCx,
|
JSContext* aCx,
|
||||||
uint64_t aMessagePortSerial,
|
uint64_t aMessagePortSerial,
|
||||||
JSAutoStructuredCloneBuffer&& aBuffer,
|
JSAutoStructuredCloneBuffer&& aBuffer,
|
||||||
nsTArray<nsCOMPtr<nsISupports>>& aClonedObjects);
|
WorkerStructuredCloneClosure& aClosure);
|
||||||
|
|
||||||
void
|
void
|
||||||
UpdateRuntimeOptions(JSContext* aCx,
|
UpdateRuntimeOptions(JSContext* aCx,
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||||
|
/* 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_workers_WorkerStructuredClone_h
|
||||||
|
#define mozilla_dom_workers_WorkerStructuredClone_h
|
||||||
|
|
||||||
|
#include "Workers.h"
|
||||||
|
#include "mozilla/dom/PMessagePort.h"
|
||||||
|
|
||||||
|
class nsPIDOMWindow;
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
class MessagePortBase;
|
||||||
|
|
||||||
|
namespace workers {
|
||||||
|
|
||||||
|
// This class is implemented in WorkerPrivate.cpp
|
||||||
|
class WorkerStructuredCloneClosure final
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
WorkerStructuredCloneClosure(const WorkerStructuredCloneClosure&) = delete;
|
||||||
|
WorkerStructuredCloneClosure & operator=(const WorkerStructuredCloneClosure&) = delete;
|
||||||
|
|
||||||
|
public:
|
||||||
|
WorkerStructuredCloneClosure();
|
||||||
|
~WorkerStructuredCloneClosure();
|
||||||
|
|
||||||
|
void Clear();
|
||||||
|
|
||||||
|
// This can be null if the MessagePort is created in a worker.
|
||||||
|
nsCOMPtr<nsPIDOMWindow> mParentWindow;
|
||||||
|
|
||||||
|
nsTArray<nsCOMPtr<nsISupports>> mClonedObjects;
|
||||||
|
|
||||||
|
// The transferred ports.
|
||||||
|
nsTArray<nsRefPtr<MessagePortBase>> mMessagePorts;
|
||||||
|
|
||||||
|
// Information for the transferring.
|
||||||
|
nsTArray<MessagePortIdentifier> mMessagePortIdentifiers;
|
||||||
|
|
||||||
|
// To avoid duplicates in the transferred ports.
|
||||||
|
nsTArray<nsRefPtr<MessagePortBase>> mTransferredPorts;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // workers namespace
|
||||||
|
} // dom namespace
|
||||||
|
} // mozilla namespace
|
||||||
|
|
||||||
|
#endif // mozilla_dom_workers_WorkerStructuredClone_h
|
|
@ -27,6 +27,7 @@
|
||||||
#include "RuntimeService.h"
|
#include "RuntimeService.h"
|
||||||
#include "WorkerPrivate.h"
|
#include "WorkerPrivate.h"
|
||||||
#include "WorkerRunnable.h"
|
#include "WorkerRunnable.h"
|
||||||
|
#include "WorkerStructuredClone.h"
|
||||||
#include "XMLHttpRequestUpload.h"
|
#include "XMLHttpRequestUpload.h"
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
|
@ -413,7 +414,7 @@ class EventRunnable final : public MainThreadProxyRunnable
|
||||||
nsString mType;
|
nsString mType;
|
||||||
nsString mResponseType;
|
nsString mResponseType;
|
||||||
JSAutoStructuredCloneBuffer mResponseBuffer;
|
JSAutoStructuredCloneBuffer mResponseBuffer;
|
||||||
nsTArray<nsCOMPtr<nsISupports> > mClonedObjects;
|
WorkerStructuredCloneClosure mResponseClosure;
|
||||||
JS::Heap<JS::Value> mResponse;
|
JS::Heap<JS::Value> mResponse;
|
||||||
nsString mResponseText;
|
nsString mResponseText;
|
||||||
nsString mResponseURL;
|
nsString mResponseURL;
|
||||||
|
@ -794,14 +795,14 @@ class SendRunnable final : public WorkerThreadProxySyncRunnable
|
||||||
{
|
{
|
||||||
nsString mStringBody;
|
nsString mStringBody;
|
||||||
JSAutoStructuredCloneBuffer mBody;
|
JSAutoStructuredCloneBuffer mBody;
|
||||||
nsTArray<nsCOMPtr<nsISupports> > mClonedObjects;
|
WorkerStructuredCloneClosure mClosure;
|
||||||
nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
|
nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
|
||||||
bool mHasUploadListeners;
|
bool mHasUploadListeners;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SendRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
|
SendRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
|
||||||
const nsAString& aStringBody, JSAutoStructuredCloneBuffer&& aBody,
|
const nsAString& aStringBody, JSAutoStructuredCloneBuffer&& aBody,
|
||||||
nsTArray<nsCOMPtr<nsISupports>>& aClonedObjects,
|
WorkerStructuredCloneClosure& aClosure,
|
||||||
nsIEventTarget* aSyncLoopTarget, bool aHasUploadListeners)
|
nsIEventTarget* aSyncLoopTarget, bool aHasUploadListeners)
|
||||||
: WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy)
|
: WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy)
|
||||||
, mStringBody(aStringBody)
|
, mStringBody(aStringBody)
|
||||||
|
@ -809,7 +810,9 @@ public:
|
||||||
, mSyncLoopTarget(aSyncLoopTarget)
|
, mSyncLoopTarget(aSyncLoopTarget)
|
||||||
, mHasUploadListeners(aHasUploadListeners)
|
, mHasUploadListeners(aHasUploadListeners)
|
||||||
{
|
{
|
||||||
mClonedObjects.SwapElements(aClonedObjects);
|
mClosure.mClonedObjects.SwapElements(aClosure.mClonedObjects);
|
||||||
|
MOZ_ASSERT(aClosure.mMessagePorts.IsEmpty());
|
||||||
|
MOZ_ASSERT(aClosure.mMessagePortIdentifiers.IsEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -1229,11 +1232,13 @@ EventRunnable::PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||||
workers::ChromeWorkerStructuredCloneCallbacks(true) :
|
workers::ChromeWorkerStructuredCloneCallbacks(true) :
|
||||||
workers::WorkerStructuredCloneCallbacks(true);
|
workers::WorkerStructuredCloneCallbacks(true);
|
||||||
|
|
||||||
nsTArray<nsCOMPtr<nsISupports> > clonedObjects;
|
WorkerStructuredCloneClosure closure;
|
||||||
|
|
||||||
if (mResponseBuffer.write(aCx, response, transferable, callbacks,
|
if (mResponseBuffer.write(aCx, response, transferable, callbacks,
|
||||||
&clonedObjects)) {
|
&closure)) {
|
||||||
mClonedObjects.SwapElements(clonedObjects);
|
mResponseClosure.mClonedObjects.SwapElements(closure.mClonedObjects);
|
||||||
|
MOZ_ASSERT(mResponseClosure.mMessagePorts.IsEmpty());
|
||||||
|
MOZ_ASSERT(mResponseClosure.mMessagePortIdentifiers.IsEmpty());
|
||||||
} else {
|
} else {
|
||||||
NS_WARNING("Failed to clone response!");
|
NS_WARNING("Failed to clone response!");
|
||||||
mResponseResult = NS_ERROR_DOM_DATA_CLONE_ERR;
|
mResponseResult = NS_ERROR_DOM_DATA_CLONE_ERR;
|
||||||
|
@ -1341,11 +1346,13 @@ EventRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||||
workers::ChromeWorkerStructuredCloneCallbacks(false) :
|
workers::ChromeWorkerStructuredCloneCallbacks(false) :
|
||||||
workers::WorkerStructuredCloneCallbacks(false);
|
workers::WorkerStructuredCloneCallbacks(false);
|
||||||
|
|
||||||
nsTArray<nsCOMPtr<nsISupports> > clonedObjects;
|
WorkerStructuredCloneClosure closure;
|
||||||
clonedObjects.SwapElements(mClonedObjects);
|
closure.mClonedObjects.SwapElements(mResponseClosure.mClonedObjects);
|
||||||
|
MOZ_ASSERT(mResponseClosure.mMessagePorts.IsEmpty());
|
||||||
|
MOZ_ASSERT(mResponseClosure.mMessagePortIdentifiers.IsEmpty());
|
||||||
|
|
||||||
JS::Rooted<JS::Value> response(aCx);
|
JS::Rooted<JS::Value> response(aCx);
|
||||||
if (!responseBuffer.read(aCx, &response, callbacks, &clonedObjects)) {
|
if (!responseBuffer.read(aCx, &response, callbacks, &closure)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1526,7 +1533,7 @@ SendRunnable::MainThreadRun()
|
||||||
workers::WorkerStructuredCloneCallbacks(true);
|
workers::WorkerStructuredCloneCallbacks(true);
|
||||||
|
|
||||||
JS::Rooted<JS::Value> body(cx);
|
JS::Rooted<JS::Value> body(cx);
|
||||||
if (mBody.read(cx, &body, callbacks, &mClonedObjects)) {
|
if (mBody.read(cx, &body, callbacks, &mClosure)) {
|
||||||
if (NS_FAILED(xpc->JSValToVariant(cx, body, getter_AddRefs(variant)))) {
|
if (NS_FAILED(xpc->JSValToVariant(cx, body, getter_AddRefs(variant)))) {
|
||||||
rv = NS_ERROR_DOM_INVALID_STATE_ERR;
|
rv = NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||||
}
|
}
|
||||||
|
@ -1536,7 +1543,7 @@ SendRunnable::MainThreadRun()
|
||||||
}
|
}
|
||||||
|
|
||||||
mBody.clear();
|
mBody.clear();
|
||||||
mClonedObjects.Clear();
|
mClosure.Clear();
|
||||||
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
|
@ -1846,7 +1853,7 @@ XMLHttpRequest::Unpin()
|
||||||
void
|
void
|
||||||
XMLHttpRequest::SendInternal(const nsAString& aStringBody,
|
XMLHttpRequest::SendInternal(const nsAString& aStringBody,
|
||||||
JSAutoStructuredCloneBuffer&& aBody,
|
JSAutoStructuredCloneBuffer&& aBody,
|
||||||
nsTArray<nsCOMPtr<nsISupports> >& aClonedObjects,
|
WorkerStructuredCloneClosure& aClosure,
|
||||||
ErrorResult& aRv)
|
ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||||
|
@ -1880,7 +1887,7 @@ XMLHttpRequest::SendInternal(const nsAString& aStringBody,
|
||||||
|
|
||||||
nsRefPtr<SendRunnable> runnable =
|
nsRefPtr<SendRunnable> runnable =
|
||||||
new SendRunnable(mWorkerPrivate, mProxy, aStringBody, Move(aBody),
|
new SendRunnable(mWorkerPrivate, mProxy, aStringBody, Move(aBody),
|
||||||
aClonedObjects, syncLoopTarget, hasUploadListeners);
|
aClosure, syncLoopTarget, hasUploadListeners);
|
||||||
if (!runnable->Dispatch(cx)) {
|
if (!runnable->Dispatch(cx)) {
|
||||||
// Dispatch() may have spun the event loop and we may have already unrooted.
|
// Dispatch() may have spun the event loop and we may have already unrooted.
|
||||||
// If so we don't want autoUnpin to try again.
|
// If so we don't want autoUnpin to try again.
|
||||||
|
@ -2102,9 +2109,9 @@ XMLHttpRequest::Send(ErrorResult& aRv)
|
||||||
|
|
||||||
// Nothing to clone.
|
// Nothing to clone.
|
||||||
JSAutoStructuredCloneBuffer buffer;
|
JSAutoStructuredCloneBuffer buffer;
|
||||||
nsTArray<nsCOMPtr<nsISupports> > clonedObjects;
|
WorkerStructuredCloneClosure closure;
|
||||||
|
|
||||||
SendInternal(NullString(), Move(buffer), clonedObjects, aRv);
|
SendInternal(NullString(), Move(buffer), closure, aRv);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -2124,9 +2131,9 @@ XMLHttpRequest::Send(const nsAString& aBody, ErrorResult& aRv)
|
||||||
|
|
||||||
// Nothing to clone.
|
// Nothing to clone.
|
||||||
JSAutoStructuredCloneBuffer buffer;
|
JSAutoStructuredCloneBuffer buffer;
|
||||||
nsTArray<nsCOMPtr<nsISupports> > clonedObjects;
|
WorkerStructuredCloneClosure closure;
|
||||||
|
|
||||||
SendInternal(aBody, Move(buffer), clonedObjects, aRv);
|
SendInternal(aBody, Move(buffer), closure, aRv);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -2167,15 +2174,15 @@ XMLHttpRequest::Send(JS::Handle<JSObject*> aBody, ErrorResult& aRv)
|
||||||
ChromeWorkerStructuredCloneCallbacks(false) :
|
ChromeWorkerStructuredCloneCallbacks(false) :
|
||||||
WorkerStructuredCloneCallbacks(false);
|
WorkerStructuredCloneCallbacks(false);
|
||||||
|
|
||||||
nsTArray<nsCOMPtr<nsISupports> > clonedObjects;
|
WorkerStructuredCloneClosure closure;
|
||||||
|
|
||||||
JSAutoStructuredCloneBuffer buffer;
|
JSAutoStructuredCloneBuffer buffer;
|
||||||
if (!buffer.write(cx, valToClone, callbacks, &clonedObjects)) {
|
if (!buffer.write(cx, valToClone, callbacks, &closure)) {
|
||||||
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
|
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SendInternal(EmptyString(), Move(buffer), clonedObjects, aRv);
|
SendInternal(EmptyString(), Move(buffer), closure, aRv);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -2213,15 +2220,15 @@ XMLHttpRequest::Send(Blob& aBody, ErrorResult& aRv)
|
||||||
ChromeWorkerStructuredCloneCallbacks(false) :
|
ChromeWorkerStructuredCloneCallbacks(false) :
|
||||||
WorkerStructuredCloneCallbacks(false);
|
WorkerStructuredCloneCallbacks(false);
|
||||||
|
|
||||||
nsTArray<nsCOMPtr<nsISupports> > clonedObjects;
|
WorkerStructuredCloneClosure closure;
|
||||||
|
|
||||||
JSAutoStructuredCloneBuffer buffer;
|
JSAutoStructuredCloneBuffer buffer;
|
||||||
if (!buffer.write(cx, value, callbacks, &clonedObjects)) {
|
if (!buffer.write(cx, value, callbacks, &closure)) {
|
||||||
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
|
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SendInternal(EmptyString(), Move(buffer), clonedObjects, aRv);
|
SendInternal(EmptyString(), Move(buffer), closure, aRv);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -2251,15 +2258,14 @@ XMLHttpRequest::Send(nsFormData& aBody, ErrorResult& aRv)
|
||||||
ChromeWorkerStructuredCloneCallbacks(false) :
|
ChromeWorkerStructuredCloneCallbacks(false) :
|
||||||
WorkerStructuredCloneCallbacks(false);
|
WorkerStructuredCloneCallbacks(false);
|
||||||
|
|
||||||
nsTArray<nsCOMPtr<nsISupports>> clonedObjects;
|
|
||||||
|
|
||||||
JSAutoStructuredCloneBuffer buffer;
|
JSAutoStructuredCloneBuffer buffer;
|
||||||
if (!buffer.write(cx, value, callbacks, &clonedObjects)) {
|
WorkerStructuredCloneClosure closure;
|
||||||
|
if (!buffer.write(cx, value, callbacks, &closure)) {
|
||||||
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
|
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SendInternal(EmptyString(), Move(buffer), clonedObjects, aRv);
|
SendInternal(EmptyString(), Move(buffer), closure, aRv);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -28,6 +28,7 @@ BEGIN_WORKERS_NAMESPACE
|
||||||
class Proxy;
|
class Proxy;
|
||||||
class XMLHttpRequestUpload;
|
class XMLHttpRequestUpload;
|
||||||
class WorkerPrivate;
|
class WorkerPrivate;
|
||||||
|
class WorkerStructuredCloneClosure;
|
||||||
|
|
||||||
class XMLHttpRequest final: public nsXHREventTarget,
|
class XMLHttpRequest final: public nsXHREventTarget,
|
||||||
public WorkerFeature
|
public WorkerFeature
|
||||||
|
@ -292,7 +293,7 @@ private:
|
||||||
void
|
void
|
||||||
SendInternal(const nsAString& aStringBody,
|
SendInternal(const nsAString& aStringBody,
|
||||||
JSAutoStructuredCloneBuffer&& aBody,
|
JSAutoStructuredCloneBuffer&& aBody,
|
||||||
nsTArray<nsCOMPtr<nsISupports> >& aClonedObjects,
|
WorkerStructuredCloneClosure& aClosure,
|
||||||
ErrorResult& aRv);
|
ErrorResult& aRv);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -79,8 +79,8 @@ onconnect = function(event) {
|
||||||
if (!("ports" in event)) {
|
if (!("ports" in event)) {
|
||||||
throw new Error("'message' event doesn't have a 'ports' property!");
|
throw new Error("'message' event doesn't have a 'ports' property!");
|
||||||
}
|
}
|
||||||
if (!(event.ports === null)) {
|
if (event.ports === null) {
|
||||||
throw new Error("'message' event has a non-null 'ports' property!");
|
throw new Error("'message' event has a null 'ports' property!");
|
||||||
}
|
}
|
||||||
event.target.postMessage(event.data);
|
event.target.postMessage(event.data);
|
||||||
throw new Error(event.data);
|
throw new Error(event.data);
|
||||||
|
|
|
@ -15,6 +15,7 @@ class nsIIPCBackgroundChildCreateCallback;
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
|
class BlobImpl;
|
||||||
class ContentChild;
|
class ContentChild;
|
||||||
class ContentParent;
|
class ContentParent;
|
||||||
class PBlobChild;
|
class PBlobChild;
|
||||||
|
@ -67,6 +68,10 @@ public:
|
||||||
GetOrCreateActorForBlob(PBackgroundChild* aBackgroundActor,
|
GetOrCreateActorForBlob(PBackgroundChild* aBackgroundActor,
|
||||||
nsIDOMBlob* aBlob);
|
nsIDOMBlob* aBlob);
|
||||||
|
|
||||||
|
static mozilla::dom::PBlobChild*
|
||||||
|
GetOrCreateActorForBlobImpl(PBackgroundChild* aBackgroundActor,
|
||||||
|
mozilla::dom::BlobImpl* aBlobImpl);
|
||||||
|
|
||||||
// See above.
|
// See above.
|
||||||
static void
|
static void
|
||||||
CloseForCurrentThread();
|
CloseForCurrentThread();
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "mozilla/dom/cache/ActorUtils.h"
|
#include "mozilla/dom/cache/ActorUtils.h"
|
||||||
#include "mozilla/dom/indexedDB/PBackgroundIDBFactoryChild.h"
|
#include "mozilla/dom/indexedDB/PBackgroundIDBFactoryChild.h"
|
||||||
#include "mozilla/dom/ipc/BlobChild.h"
|
#include "mozilla/dom/ipc/BlobChild.h"
|
||||||
|
#include "mozilla/dom/MessagePortChild.h"
|
||||||
#include "mozilla/ipc/PBackgroundTestChild.h"
|
#include "mozilla/ipc/PBackgroundTestChild.h"
|
||||||
#include "mozilla/layout/VsyncChild.h"
|
#include "mozilla/layout/VsyncChild.h"
|
||||||
#include "mozilla/net/PUDPSocketChild.h"
|
#include "mozilla/net/PUDPSocketChild.h"
|
||||||
|
@ -340,6 +341,28 @@ BackgroundChildImpl::DeallocPMediaChild(media::PMediaChild *aActor)
|
||||||
return media::DeallocPMediaChild(aActor);
|
return media::DeallocPMediaChild(aActor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// MessageChannel/MessagePort API
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
dom::PMessagePortChild*
|
||||||
|
BackgroundChildImpl::AllocPMessagePortChild(const nsID& aUUID,
|
||||||
|
const nsID& aDestinationUUID,
|
||||||
|
const uint32_t& aSequenceID)
|
||||||
|
{
|
||||||
|
nsRefPtr<dom::MessagePortChild> agent = new dom::MessagePortChild();
|
||||||
|
return agent.forget().take();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
BackgroundChildImpl::DeallocPMessagePortChild(PMessagePortChild* aActor)
|
||||||
|
{
|
||||||
|
nsRefPtr<dom::MessagePortChild> child =
|
||||||
|
dont_AddRef(static_cast<dom::MessagePortChild*>(aActor));
|
||||||
|
MOZ_ASSERT(child);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ipc
|
} // namespace ipc
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
|
|
|
@ -121,6 +121,13 @@ protected:
|
||||||
|
|
||||||
virtual bool
|
virtual bool
|
||||||
DeallocPCacheStreamControlChild(dom::cache::PCacheStreamControlChild* aActor) override;
|
DeallocPCacheStreamControlChild(dom::cache::PCacheStreamControlChild* aActor) override;
|
||||||
|
|
||||||
|
virtual PMessagePortChild*
|
||||||
|
AllocPMessagePortChild(const nsID& aUUID, const nsID& aDestinationUUID,
|
||||||
|
const uint32_t& aSequenceID) override;
|
||||||
|
|
||||||
|
virtual bool
|
||||||
|
DeallocPMessagePortChild(PMessagePortChild* aActor) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BackgroundChildImpl::ThreadLocal final
|
class BackgroundChildImpl::ThreadLocal final
|
||||||
|
|
|
@ -914,17 +914,27 @@ PBlobChild*
|
||||||
BackgroundChild::GetOrCreateActorForBlob(PBackgroundChild* aBackgroundActor,
|
BackgroundChild::GetOrCreateActorForBlob(PBackgroundChild* aBackgroundActor,
|
||||||
nsIDOMBlob* aBlob)
|
nsIDOMBlob* aBlob)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aBackgroundActor);
|
|
||||||
MOZ_ASSERT(aBlob);
|
MOZ_ASSERT(aBlob);
|
||||||
|
|
||||||
|
nsRefPtr<BlobImpl> blobImpl = static_cast<Blob*>(aBlob)->Impl();
|
||||||
|
MOZ_ASSERT(blobImpl);
|
||||||
|
|
||||||
|
return GetOrCreateActorForBlobImpl(aBackgroundActor, blobImpl);
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
PBlobChild*
|
||||||
|
BackgroundChild::GetOrCreateActorForBlobImpl(PBackgroundChild* aBackgroundActor,
|
||||||
|
BlobImpl* aBlobImpl)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aBackgroundActor);
|
||||||
|
MOZ_ASSERT(aBlobImpl);
|
||||||
MOZ_ASSERT(GetForCurrentThread(),
|
MOZ_ASSERT(GetForCurrentThread(),
|
||||||
"BackgroundChild not created on this thread yet!");
|
"BackgroundChild not created on this thread yet!");
|
||||||
MOZ_ASSERT(aBackgroundActor == GetForCurrentThread(),
|
MOZ_ASSERT(aBackgroundActor == GetForCurrentThread(),
|
||||||
"BackgroundChild is bound to a different thread!");
|
"BackgroundChild is bound to a different thread!");
|
||||||
|
|
||||||
nsRefPtr<BlobImpl> blobImpl = static_cast<Blob*>(aBlob)->Impl();
|
BlobChild* actor = BlobChild::GetOrCreate(aBackgroundActor, aBlobImpl);
|
||||||
MOZ_ASSERT(blobImpl);
|
|
||||||
|
|
||||||
BlobChild* actor = BlobChild::GetOrCreate(aBackgroundActor, blobImpl);
|
|
||||||
if (NS_WARN_IF(!actor)) {
|
if (NS_WARN_IF(!actor)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "mozilla/Assertions.h"
|
#include "mozilla/Assertions.h"
|
||||||
#include "mozilla/dom/ContentParent.h"
|
#include "mozilla/dom/ContentParent.h"
|
||||||
#include "mozilla/dom/PBlobParent.h"
|
#include "mozilla/dom/PBlobParent.h"
|
||||||
|
#include "mozilla/dom/MessagePortParent.h"
|
||||||
#include "mozilla/dom/ServiceWorkerRegistrar.h"
|
#include "mozilla/dom/ServiceWorkerRegistrar.h"
|
||||||
#include "mozilla/dom/cache/ActorUtils.h"
|
#include "mozilla/dom/cache/ActorUtils.h"
|
||||||
#include "mozilla/dom/indexedDB/ActorsParent.h"
|
#include "mozilla/dom/indexedDB/ActorsParent.h"
|
||||||
|
@ -39,6 +40,8 @@ using mozilla::ipc::AssertIsOnBackgroundThread;
|
||||||
using mozilla::dom::cache::PCacheParent;
|
using mozilla::dom::cache::PCacheParent;
|
||||||
using mozilla::dom::cache::PCacheStorageParent;
|
using mozilla::dom::cache::PCacheStorageParent;
|
||||||
using mozilla::dom::cache::PCacheStreamControlParent;
|
using mozilla::dom::cache::PCacheStreamControlParent;
|
||||||
|
using mozilla::dom::MessagePortParent;
|
||||||
|
using mozilla::dom::PMessagePortParent;
|
||||||
using mozilla::dom::UDPSocketParent;
|
using mozilla::dom::UDPSocketParent;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -563,6 +566,41 @@ BackgroundParentImpl::DeallocPCacheStreamControlParent(PCacheStreamControlParent
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PMessagePortParent*
|
||||||
|
BackgroundParentImpl::AllocPMessagePortParent(const nsID& aUUID,
|
||||||
|
const nsID& aDestinationUUID,
|
||||||
|
const uint32_t& aSequenceID)
|
||||||
|
{
|
||||||
|
AssertIsInMainProcess();
|
||||||
|
AssertIsOnBackgroundThread();
|
||||||
|
|
||||||
|
return new MessagePortParent(aUUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
BackgroundParentImpl::RecvPMessagePortConstructor(PMessagePortParent* aActor,
|
||||||
|
const nsID& aUUID,
|
||||||
|
const nsID& aDestinationUUID,
|
||||||
|
const uint32_t& aSequenceID)
|
||||||
|
{
|
||||||
|
AssertIsInMainProcess();
|
||||||
|
AssertIsOnBackgroundThread();
|
||||||
|
|
||||||
|
MessagePortParent* mp = static_cast<MessagePortParent*>(aActor);
|
||||||
|
return mp->Entangle(aDestinationUUID, aSequenceID);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
BackgroundParentImpl::DeallocPMessagePortParent(PMessagePortParent* aActor)
|
||||||
|
{
|
||||||
|
AssertIsInMainProcess();
|
||||||
|
AssertIsOnBackgroundThread();
|
||||||
|
MOZ_ASSERT(aActor);
|
||||||
|
|
||||||
|
delete static_cast<MessagePortParent*>(aActor);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ipc
|
} // namespace ipc
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
|
|
|
@ -129,6 +129,20 @@ protected:
|
||||||
const nsCString& aFilter) override;
|
const nsCString& aFilter) override;
|
||||||
virtual bool
|
virtual bool
|
||||||
DeallocPUDPSocketParent(PUDPSocketParent*) override;
|
DeallocPUDPSocketParent(PUDPSocketParent*) override;
|
||||||
|
|
||||||
|
virtual PMessagePortParent*
|
||||||
|
AllocPMessagePortParent(const nsID& aUUID,
|
||||||
|
const nsID& aDestinationUUID,
|
||||||
|
const uint32_t& aSequenceID) override;
|
||||||
|
|
||||||
|
virtual bool
|
||||||
|
RecvPMessagePortConstructor(PMessagePortParent* aActor,
|
||||||
|
const nsID& aUUID,
|
||||||
|
const nsID& aDestinationUUID,
|
||||||
|
const uint32_t& aSequenceID) override;
|
||||||
|
|
||||||
|
virtual bool
|
||||||
|
DeallocPMessagePortParent(PMessagePortParent* aActor) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ipc
|
} // namespace ipc
|
||||||
|
|
|
@ -10,6 +10,7 @@ include protocol PCache;
|
||||||
include protocol PCacheStorage;
|
include protocol PCacheStorage;
|
||||||
include protocol PCacheStreamControl;
|
include protocol PCacheStreamControl;
|
||||||
include protocol PFileDescriptorSet;
|
include protocol PFileDescriptorSet;
|
||||||
|
include protocol PMessagePort;
|
||||||
include protocol PMedia;
|
include protocol PMedia;
|
||||||
include protocol PServiceWorkerManager;
|
include protocol PServiceWorkerManager;
|
||||||
include protocol PUDPSocket;
|
include protocol PUDPSocket;
|
||||||
|
@ -35,6 +36,7 @@ sync protocol PBackground
|
||||||
manages PCacheStorage;
|
manages PCacheStorage;
|
||||||
manages PCacheStreamControl;
|
manages PCacheStreamControl;
|
||||||
manages PFileDescriptorSet;
|
manages PFileDescriptorSet;
|
||||||
|
manages PMessagePort;
|
||||||
manages PMedia;
|
manages PMedia;
|
||||||
manages PServiceWorkerManager;
|
manages PServiceWorkerManager;
|
||||||
manages PUDPSocket;
|
manages PUDPSocket;
|
||||||
|
@ -59,6 +61,8 @@ parent:
|
||||||
|
|
||||||
PCacheStorage(Namespace aNamespace, PrincipalInfo aPrincipalInfo);
|
PCacheStorage(Namespace aNamespace, PrincipalInfo aPrincipalInfo);
|
||||||
|
|
||||||
|
PMessagePort(nsID uuid, nsID destinationUuid, uint32_t sequenceId);
|
||||||
|
|
||||||
child:
|
child:
|
||||||
PCache();
|
PCache();
|
||||||
PCacheStreamControl();
|
PCacheStreamControl();
|
||||||
|
|
|
@ -148,7 +148,7 @@ JS_WriteStructuredClone(JSContext* cx, JS::HandleValue v, uint64_t** datap, size
|
||||||
JS_PUBLIC_API(bool)
|
JS_PUBLIC_API(bool)
|
||||||
JS_ClearStructuredClone(uint64_t* data, size_t nbytes,
|
JS_ClearStructuredClone(uint64_t* data, size_t nbytes,
|
||||||
const JSStructuredCloneCallbacks* optionalCallbacks,
|
const JSStructuredCloneCallbacks* optionalCallbacks,
|
||||||
void* closure);
|
void *closure, bool freeData = true);
|
||||||
|
|
||||||
JS_PUBLIC_API(bool)
|
JS_PUBLIC_API(bool)
|
||||||
JS_StructuredCloneHasTransferables(const uint64_t* data, size_t nbytes, bool* hasTransferable);
|
JS_StructuredCloneHasTransferables(const uint64_t* data, size_t nbytes, bool* hasTransferable);
|
||||||
|
|
|
@ -1908,10 +1908,12 @@ JS_WriteStructuredClone(JSContext* cx, HandleValue value, uint64_t** bufp, size_
|
||||||
JS_PUBLIC_API(bool)
|
JS_PUBLIC_API(bool)
|
||||||
JS_ClearStructuredClone(uint64_t* data, size_t nbytes,
|
JS_ClearStructuredClone(uint64_t* data, size_t nbytes,
|
||||||
const JSStructuredCloneCallbacks* optionalCallbacks,
|
const JSStructuredCloneCallbacks* optionalCallbacks,
|
||||||
void* closure)
|
void* closure, bool freeData)
|
||||||
{
|
{
|
||||||
DiscardTransferables(data, nbytes, optionalCallbacks, closure);
|
DiscardTransferables(data, nbytes, optionalCallbacks, closure);
|
||||||
|
if (freeData) {
|
||||||
js_free(data);
|
js_free(data);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[event-ports-dedicated.html]
|
|
||||||
type: testharness
|
|
||||||
[e.ports in dedicated worker]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче