Bug 776832 - Add a scriptable API to assert app permissions through messagemanager. r=smaug

This commit is contained in:
Philipp von Weitershausen 2012-09-27 22:43:12 -07:00
parent b2b6d9dcdb
commit ce02d379ee
16 changed files with 657 additions and 319 deletions

View File

@ -335,3 +335,30 @@ interface nsIFrameScriptLoader : nsISupports
*/
void removeDelayedFrameScript(in AString aURL);
};
[scriptable, builtinclass, uuid(5f552699-01a2-4f17-833b-ddb3fa0d98b2)]
interface nsIPermissionChecker : nsISupports
{
/**
* Return true iff the "remote" process has |aPermission|. This is
* intended to be used by JS implementations of cross-process DOM
* APIs, like so
*
* recvFooRequest: function(message) {
* if (!message.target.assertPermission("foo")) {
* return false;
* }
* // service foo request
*
* This interface only returns meaningful data when our content is
* in a separate process. If it shares the same OS process as us,
* then applying this permission check doesn't add any security,
* though it doesn't hurt anything either.
*
* Note: If the remote content process does *not* have |aPermission|,
* it will be killed as a precaution.
*/
boolean assertPermission(in DOMString aPermission);
};

View File

@ -120,11 +120,11 @@ MarkMessageManagers()
nsCOMPtr<nsIMessageSender> tabMM = do_QueryInterface(childMM);
tabMM->MarkForCC();
//XXX hack warning, but works, since we know that
// callback data is frameloader.
void* cb = static_cast<nsFrameMessageManager*>(tabMM.get())->
GetCallbackData();
nsFrameLoader* fl = static_cast<nsFrameLoader*>(cb);
if (fl) {
// callback is frameloader.
mozilla::dom::ipc::MessageManagerCallback* cb =
static_cast<nsFrameMessageManager*>(tabMM.get())->GetCallback();
if (cb) {
nsFrameLoader* fl = static_cast<nsFrameLoader*>(cb);
nsIDOMEventTarget* et = fl->GetTabChildGlobalAsEventTarget();
if (!et) {
continue;

View File

@ -76,6 +76,7 @@
#include "Layers.h"
#include "AppProcessPermissions.h"
#include "ContentParent.h"
#include "TabParent.h"
#include "mozilla/GuardObjects.h"
@ -97,6 +98,7 @@
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::dom::ipc;
using namespace mozilla::layers;
using namespace mozilla::layout;
typedef FrameMetrics::ViewID ViewID;
@ -1257,13 +1259,13 @@ nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
mMessageManager->RemoveFromParent();
mMessageManager->SetJSContext(otherCx);
mMessageManager->SetParentManager(otherParentManager);
mMessageManager->SetCallbackData(aOther, false);
mMessageManager->SetCallback(aOther, false);
}
if (aOther->mMessageManager) {
aOther->mMessageManager->RemoveFromParent();
aOther->mMessageManager->SetJSContext(thisCx);
aOther->mMessageManager->SetParentManager(ourParentManager);
aOther->mMessageManager->SetCallbackData(this, false);
aOther->mMessageManager->SetCallback(this, false);
}
mMessageManager.swap(aOther->mMessageManager);
@ -2155,16 +2157,15 @@ nsFrameLoader::CreateStaticClone(nsIFrameLoader* aDest)
return NS_OK;
}
bool LoadScript(void* aCallbackData, const nsAString& aURL)
bool
nsFrameLoader::DoLoadFrameScript(const nsAString& aURL)
{
mozilla::dom::PBrowserParent* tabParent =
static_cast<nsFrameLoader*>(aCallbackData)->GetRemoteBrowser();
mozilla::dom::PBrowserParent* tabParent = GetRemoteBrowser();
if (tabParent) {
return tabParent->SendLoadRemoteScript(nsString(aURL));
}
nsFrameLoader* fl = static_cast<nsFrameLoader*>(aCallbackData);
nsRefPtr<nsInProcessTabChildGlobal> tabChild =
static_cast<nsInProcessTabChildGlobal*>(fl->GetTabChildGlobalAsEventTarget());
static_cast<nsInProcessTabChildGlobal*>(GetTabChildGlobalAsEventTarget());
if (tabChild) {
tabChild->LoadFrameScript(aURL);
}
@ -2175,8 +2176,8 @@ class nsAsyncMessageToChild : public nsRunnable
{
public:
nsAsyncMessageToChild(nsFrameLoader* aFrameLoader,
const nsAString& aMessage,
const StructuredCloneData& aData)
const nsAString& aMessage,
const StructuredCloneData& aData)
: mFrameLoader(aFrameLoader), mMessage(aMessage)
{
if (aData.mDataLength && !mData.copy(aData.mData, aData.mDataLength)) {
@ -2209,12 +2210,11 @@ public:
StructuredCloneClosure mClosure;
};
bool SendAsyncMessageToChild(void* aCallbackData,
const nsAString& aMessage,
const StructuredCloneData& aData)
bool
nsFrameLoader::DoSendAsyncMessage(const nsAString& aMessage,
const StructuredCloneData& aData)
{
PBrowserParent* tabParent =
static_cast<nsFrameLoader*>(aCallbackData)->GetRemoteBrowser();
PBrowserParent* tabParent = GetRemoteBrowser();
if (tabParent) {
ClonedMessageData data;
@ -2244,10 +2244,8 @@ bool SendAsyncMessageToChild(void* aCallbackData,
return tabParent->SendAsyncMessage(nsString(aMessage), data);
}
if (static_cast<nsFrameLoader*>(aCallbackData)->mChildMessageManager) {
nsRefPtr<nsIRunnable> ev =
new nsAsyncMessageToChild(static_cast<nsFrameLoader*>(aCallbackData),
aMessage, aData);
if (mChildMessageManager) {
nsRefPtr<nsIRunnable> ev = new nsAsyncMessageToChild(this, aMessage, aData);
NS_DispatchToCurrentThread(ev);
return true;
}
@ -2256,6 +2254,13 @@ bool SendAsyncMessageToChild(void* aCallbackData,
return false;
}
bool
nsFrameLoader::CheckPermission(const nsAString& aPermission)
{
return AssertAppProcessPermission(GetRemoteBrowser(),
NS_ConvertUTF16toUTF8(aPermission).get());
}
NS_IMETHODIMP
nsFrameLoader::GetMessageManager(nsIMessageSender** aManager)
{
@ -2336,7 +2341,7 @@ nsFrameLoader::EnsureMessageManager()
if (mMessageManager) {
if (ShouldUseRemoteProcess()) {
mMessageManager->SetCallbackData(mRemoteBrowserShown ? this : nullptr);
mMessageManager->SetCallback(mRemoteBrowserShown ? this : nullptr);
}
return NS_OK;
}
@ -2355,24 +2360,20 @@ nsFrameLoader::EnsureMessageManager()
}
if (ShouldUseRemoteProcess()) {
mMessageManager = new nsFrameMessageManager(true, /* aChrome */
nullptr,
SendAsyncMessageToChild,
LoadScript,
mRemoteBrowserShown ? this : nullptr,
mMessageManager = new nsFrameMessageManager(mRemoteBrowserShown ? this : nullptr,
static_cast<nsFrameMessageManager*>(parentManager.get()),
cx);
cx,
MM_CHROME);
} else {
mMessageManager = new nsFrameMessageManager(true, /* aChrome */
nullptr,
SendAsyncMessageToChild,
LoadScript,
nullptr,
mMessageManager = new nsFrameMessageManager(nullptr,
static_cast<nsFrameMessageManager*>(parentManager.get()),
cx);
cx,
MM_CHROME);
mChildMessageManager =
new nsInProcessTabChildGlobal(mDocShell, mOwnerContent, mMessageManager);
mMessageManager->SetCallbackData(this);
// Force pending frame scripts to be loaded.
mMessageManager->SetCallback(this);
}
return NS_OK;
}

View File

@ -38,6 +38,7 @@ namespace mozilla {
namespace dom {
class PBrowserParent;
class TabParent;
struct StructuredCloneData;
}
namespace layout {
@ -140,7 +141,8 @@ private:
class nsFrameLoader MOZ_FINAL : public nsIFrameLoader,
public nsIContentViewManager,
public nsStubMutationObserver
public nsStubMutationObserver,
public mozilla::dom::ipc::MessageManagerCallback
{
friend class AutoResetInShow;
typedef mozilla::dom::PBrowserParent PBrowserParent;
@ -179,6 +181,15 @@ public:
nsIDOMEventTarget* GetTabChildGlobalAsEventTarget();
nsresult CreateStaticClone(nsIFrameLoader* aDest);
/**
* MessageManagerCallback methods that we override.
*/
virtual bool DoLoadFrameScript(const nsAString& aURL);
virtual bool DoSendAsyncMessage(const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData);
virtual bool CheckPermission(const nsAString& aPermission);
/**
* Called from the layout frame associated with this frame loader;
* this notifies us to hook up with the widget and view.

View File

@ -7,6 +7,7 @@
#include "nsFrameMessageManager.h"
#include "AppProcessPermissions.h"
#include "ContentChild.h"
#include "ContentParent.h"
#include "nsContentUtils.h"
@ -17,6 +18,7 @@
#include "nsJSPrincipals.h"
#include "nsNetUtil.h"
#include "nsScriptLoader.h"
#include "nsFrameLoader.h"
#include "nsIJSContextStack.h"
#include "nsIXULRuntime.h"
#include "nsIScriptError.h"
@ -39,6 +41,8 @@
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::dom::ipc;
static bool
IsChromeProcess()
@ -103,6 +107,10 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFrameMessageManager)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIFrameScriptLoader,
mChrome && !mIsProcessManager)
/* Message senders in the chrome process support nsIPermissionChecker. */
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIPermissionChecker,
mChrome && !mIsBroadcaster)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(ChromeMessageBroadcaster,
mChrome && mIsBroadcaster)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(ChromeMessageSender,
@ -159,18 +167,18 @@ nsFrameMessageManager::LoadFrameScript(const nsAString& aURL,
if (IsGlobal() || IsWindowLevel()) {
// Cache for future windows or frames
mPendingScripts.AppendElement(aURL);
} else if (!mCallbackData) {
} else if (!mCallback) {
// We're frame message manager, which isn't connected yet.
mPendingScripts.AppendElement(aURL);
return NS_OK;
}
}
if (mCallbackData) {
if (mCallback) {
#ifdef DEBUG_smaug
printf("Will load %s \n", NS_ConvertUTF16toUTF8(aURL).get());
#endif
NS_ENSURE_TRUE(mLoadScriptCallback(mCallbackData, aURL), NS_ERROR_FAILURE);
NS_ENSURE_TRUE(mCallback->DoLoadFrameScript(aURL), NS_ERROR_FAILURE);
}
for (int32_t i = 0; i < mChildManagers.Count(); ++i) {
@ -242,62 +250,60 @@ nsFrameMessageManager::SendSyncMessage(const nsAString& aMessageName,
NS_ASSERTION(!IsGlobal(), "Should not call SendSyncMessage in chrome");
NS_ASSERTION(!IsWindowLevel(), "Should not call SendSyncMessage in chrome");
NS_ASSERTION(!mParentManager, "Should not have parent manager in content!");
*aRetval = JSVAL_VOID;
if (mSyncCallback) {
NS_ENSURE_TRUE(mCallbackData, NS_ERROR_NOT_INITIALIZED);
StructuredCloneData data;
JSAutoStructuredCloneBuffer buffer;
if (aArgc >= 2 &&
!GetParamsForMessage(aCx, aObject, buffer, data.mClosure)) {
return NS_ERROR_DOM_DATA_CLONE_ERR;
}
data.mData = buffer.data();
data.mDataLength = buffer.nbytes();
NS_ENSURE_TRUE(mCallback, NS_ERROR_NOT_INITIALIZED);
InfallibleTArray<nsString> retval;
if (mSyncCallback(mCallbackData, aMessageName, data, &retval)) {
JSAutoRequest ar(aCx);
uint32_t len = retval.Length();
JSObject* dataArray = JS_NewArrayObject(aCx, len, NULL);
NS_ENSURE_TRUE(dataArray, NS_ERROR_OUT_OF_MEMORY);
StructuredCloneData data;
JSAutoStructuredCloneBuffer buffer;
if (aArgc >= 2 &&
!GetParamsForMessage(aCx, aObject, buffer, data.mClosure)) {
return NS_ERROR_DOM_DATA_CLONE_ERR;
}
data.mData = buffer.data();
data.mDataLength = buffer.nbytes();
for (uint32_t i = 0; i < len; ++i) {
if (retval[i].IsEmpty()) {
continue;
}
InfallibleTArray<nsString> retval;
if (mCallback->DoSendSyncMessage(aMessageName, data, &retval)) {
JSAutoRequest ar(aCx);
uint32_t len = retval.Length();
JSObject* dataArray = JS_NewArrayObject(aCx, len, NULL);
NS_ENSURE_TRUE(dataArray, NS_ERROR_OUT_OF_MEMORY);
jsval ret = JSVAL_VOID;
if (!JS_ParseJSON(aCx, static_cast<const jschar*>(retval[i].get()),
retval[i].Length(), &ret)) {
return NS_ERROR_UNEXPECTED;
}
NS_ENSURE_TRUE(JS_SetElement(aCx, dataArray, i, &ret), NS_ERROR_OUT_OF_MEMORY);
for (uint32_t i = 0; i < len; ++i) {
if (retval[i].IsEmpty()) {
continue;
}
*aRetval = OBJECT_TO_JSVAL(dataArray);
jsval ret = JSVAL_VOID;
if (!JS_ParseJSON(aCx, static_cast<const jschar*>(retval[i].get()),
retval[i].Length(), &ret)) {
return NS_ERROR_UNEXPECTED;
}
NS_ENSURE_TRUE(JS_SetElement(aCx, dataArray, i, &ret), NS_ERROR_OUT_OF_MEMORY);
}
*aRetval = OBJECT_TO_JSVAL(dataArray);
}
return NS_OK;
}
nsresult
nsFrameMessageManager::DispatchAsyncMessageInternal(const nsAString& aMessage,
const StructuredCloneData& aData,
ShouldBroadcast aBroadcast)
const StructuredCloneData& aData)
{
if (mAsyncCallback) {
NS_ENSURE_TRUE(mCallbackData, NS_ERROR_NOT_INITIALIZED);
if (!mAsyncCallback(mCallbackData, aMessage, aData)) {
return NS_ERROR_FAILURE;
}
}
if (aBroadcast == BROADCAST) {
if (mIsBroadcaster) {
int32_t len = mChildManagers.Count();
for (int32_t i = 0; i < len; ++i) {
static_cast<nsFrameMessageManager*>(mChildManagers[i])->
DispatchAsyncMessageInternal(aMessage, aData, aBroadcast);
DispatchAsyncMessageInternal(aMessage, aData);
}
return NS_OK;
}
NS_ENSURE_TRUE(mCallback, NS_ERROR_NOT_INITIALIZED);
if (!mCallback->DoSendAsyncMessage(aMessage, aData)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
@ -306,8 +312,7 @@ nsresult
nsFrameMessageManager::DispatchAsyncMessage(const nsAString& aMessageName,
const jsval& aObject,
JSContext* aCx,
uint8_t aArgc,
ShouldBroadcast aBroadcast)
uint8_t aArgc)
{
StructuredCloneData data;
JSAutoStructuredCloneBuffer buffer;
@ -320,7 +325,7 @@ nsFrameMessageManager::DispatchAsyncMessage(const nsAString& aMessageName,
data.mData = buffer.data();
data.mDataLength = buffer.nbytes();
return DispatchAsyncMessageInternal(aMessageName, data, aBroadcast);
return DispatchAsyncMessageInternal(aMessageName, data);
}
@ -332,7 +337,7 @@ nsFrameMessageManager::SendAsyncMessage(const nsAString& aMessageName,
JSContext* aCx,
uint8_t aArgc)
{
return DispatchAsyncMessage(aMessageName, aObject, aCx, aArgc, DONT_BROADCAST);
return DispatchAsyncMessage(aMessageName, aObject, aCx, aArgc);
}
@ -344,7 +349,7 @@ nsFrameMessageManager::BroadcastAsyncMessage(const nsAString& aMessageName,
JSContext* aCx,
uint8_t aArgc)
{
return DispatchAsyncMessage(aMessageName, aObject, aCx, aArgc, BROADCAST);
return DispatchAsyncMessage(aMessageName, aObject, aCx, aArgc);
}
NS_IMETHODIMP
@ -418,6 +423,23 @@ nsFrameMessageManager::Atob(const nsAString& aAsciiString,
return NS_OK;
}
// nsIPermissionChecker
NS_IMETHODIMP
nsFrameMessageManager::AssertPermission(const nsAString& aPermission, bool* aHasPermission)
{
*aHasPermission = false;
// This API is only supported for message senders in the chrome process.
if (!mChrome || mIsBroadcaster) {
return NS_ERROR_NOT_IMPLEMENTED;
}
if (!mCallback) {
return NS_ERROR_NOT_AVAILABLE;
}
*aHasPermission = mCallback->CheckPermission(aPermission);
return NS_OK;
}
class MMListenerRemover
{
@ -610,10 +632,15 @@ nsFrameMessageManager::AddChildManager(nsFrameMessageManager* aManager,
}
void
nsFrameMessageManager::SetCallbackData(void* aData, bool aLoadScripts)
nsFrameMessageManager::SetCallback(MessageManagerCallback* aCallback, bool aLoadScripts)
{
if (aData && mCallbackData != aData) {
mCallbackData = aData;
NS_ASSERTION(!mIsBroadcaster || !mCallback,
"Broadcasters cannot have callbacks!");
if (aCallback && mCallback != aCallback) {
mCallback = aCallback;
if (mOwnsCallback) {
mOwnedCallback = aCallback;
}
// First load global scripts by adding this to parent manager.
if (mParentManager) {
mParentManager->AddChildManager(this, aLoadScripts);
@ -633,7 +660,8 @@ nsFrameMessageManager::RemoveFromParent()
mParentManager->RemoveChildManager(this);
}
mParentManager = nullptr;
mCallbackData = nullptr;
mCallback = nullptr;
mOwnedCallback = nullptr;
mContext = nullptr;
}
@ -645,7 +673,8 @@ nsFrameMessageManager::Disconnect(bool aRemoveFromParent)
}
mDisconnected = true;
mParentManager = nullptr;
mCallbackData = nullptr;
mCallback = nullptr;
mOwnedCallback = nullptr;
mContext = nullptr;
if (!mHandlingMessage) {
mListeners.Clear();
@ -656,17 +685,10 @@ nsresult
NS_NewGlobalMessageManager(nsIMessageBroadcaster** aResult)
{
NS_ENSURE_TRUE(IsChromeProcess(), NS_ERROR_NOT_AVAILABLE);
nsFrameMessageManager* mm = new nsFrameMessageManager(true /* aChrome */,
nsFrameMessageManager* mm = new nsFrameMessageManager(nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
true /* aGlobal */,
false /* aProcessManager */,
true /* aBroadcaster */);
NS_ENSURE_TRUE(mm, NS_ERROR_OUT_OF_MEMORY);
MM_CHROME | MM_GLOBAL | MM_BROADCASTER);
return CallQueryInterface(mm, aResult);
}
@ -1001,36 +1023,6 @@ nsFrameMessageManager* nsFrameMessageManager::sParentProcessManager = nullptr;
nsFrameMessageManager* nsFrameMessageManager::sSameProcessParentManager = nullptr;
nsTArray<nsCOMPtr<nsIRunnable> >* nsFrameMessageManager::sPendingSameProcessAsyncMessages = nullptr;
bool SendAsyncMessageToChildProcess(void* aCallbackData,
const nsAString& aMessage,
const StructuredCloneData& aData)
{
mozilla::dom::ContentParent* cp =
static_cast<mozilla::dom::ContentParent*>(aCallbackData);
NS_WARN_IF_FALSE(cp, "No child process!");
if (cp) {
ClonedMessageData data;
SerializedStructuredCloneBuffer& buffer = data.data();
buffer.data = aData.mData;
buffer.dataLength = aData.mDataLength;
const nsTArray<nsCOMPtr<nsIDOMBlob> >& blobs = aData.mClosure.mBlobs;
if (!blobs.IsEmpty()) {
InfallibleTArray<PBlobParent*>& blobParents = data.blobsParent();
uint32_t length = blobs.Length();
blobParents.SetCapacity(length);
for (uint32_t i = 0; i < length; ++i) {
BlobParent* blobParent = cp->GetOrCreateActorForBlob(blobs[i]);
if (!blobParent) {
return false;
}
blobParents.AppendElement(blobParent);
}
}
return cp->SendAsyncMessage(nsString(aMessage), data);
}
return true;
}
class nsAsyncMessageToSameProcessChild : public nsRunnable
{
@ -1064,24 +1056,64 @@ public:
StructuredCloneClosure mClosure;
};
bool SendAsyncMessageToSameProcessChild(void* aCallbackData,
const nsAString& aMessage,
const StructuredCloneData& aData)
{
nsRefPtr<nsIRunnable> ev =
new nsAsyncMessageToSameProcessChild(aMessage, aData);
NS_DispatchToCurrentThread(ev);
return true;
}
bool SendSyncMessageToParentProcess(void* aCallbackData,
const nsAString& aMessage,
const StructuredCloneData& aData,
InfallibleTArray<nsString>* aJSONRetVal)
/**
* Send messages to an imaginary child process in a single-process scenario.
*/
class SameParentProcessMessageManagerCallback : public MessageManagerCallback
{
mozilla::dom::ContentChild* cc =
mozilla::dom::ContentChild::GetSingleton();
if (cc) {
public:
SameParentProcessMessageManagerCallback()
{
MOZ_COUNT_CTOR(SameParentProcessMessageManagerCallback);
}
virtual ~SameParentProcessMessageManagerCallback()
{
MOZ_COUNT_DTOR(SameParentProcessMessageManagerCallback);
}
virtual bool DoSendAsyncMessage(const nsAString& aMessage,
const StructuredCloneData& aData)
{
nsRefPtr<nsIRunnable> ev =
new nsAsyncMessageToSameProcessChild(aMessage, aData);
NS_DispatchToCurrentThread(ev);
return true;
}
bool CheckPermission(const nsAString& aPermission)
{
// In a single-process scenario, the child always has all capabilities.
return true;
}
};
/**
* Send messages to the parent process.
*/
class ChildProcessMessageManagerCallback : public MessageManagerCallback
{
public:
ChildProcessMessageManagerCallback()
{
MOZ_COUNT_CTOR(ChildProcessMessageManagerCallback);
}
virtual ~ChildProcessMessageManagerCallback()
{
MOZ_COUNT_DTOR(ChildProcessMessageManagerCallback);
}
virtual bool DoSendSyncMessage(const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
InfallibleTArray<nsString>* aJSONRetVal)
{
mozilla::dom::ContentChild* cc =
mozilla::dom::ContentChild::GetSingleton();
if (!cc) {
return true;
}
ClonedMessageData data;
SerializedStructuredCloneBuffer& buffer = data.data();
buffer.data = aData.mData;
@ -1099,41 +1131,17 @@ bool SendSyncMessageToParentProcess(void* aCallbackData,
blobChildList.AppendElement(blobChild);
}
}
return
cc->SendSyncMessage(nsString(aMessage), data, aJSONRetVal);
return cc->SendSyncMessage(nsString(aMessage), data, aJSONRetVal);
}
return true;
}
bool SendSyncMessageToSameProcessParent(void* aCallbackData,
const nsAString& aMessage,
const StructuredCloneData& aData,
InfallibleTArray<nsString>* aJSONRetVal)
{
nsTArray<nsCOMPtr<nsIRunnable> > asyncMessages;
if (nsFrameMessageManager::sPendingSameProcessAsyncMessages) {
asyncMessages.SwapElements(*nsFrameMessageManager::sPendingSameProcessAsyncMessages);
uint32_t len = asyncMessages.Length();
for (uint32_t i = 0; i < len; ++i) {
nsCOMPtr<nsIRunnable> async = asyncMessages[i];
async->Run();
virtual bool DoSendAsyncMessage(const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData)
{
mozilla::dom::ContentChild* cc =
mozilla::dom::ContentChild::GetSingleton();
if (!cc) {
return true;
}
}
if (nsFrameMessageManager::sSameProcessParentManager) {
nsRefPtr<nsFrameMessageManager> ppm = nsFrameMessageManager::sSameProcessParentManager;
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), aMessage,
true, &aData, nullptr, aJSONRetVal);
}
return true;
}
bool SendAsyncMessageToParentProcess(void* aCallbackData,
const nsAString& aMessage,
const StructuredCloneData& aData)
{
mozilla::dom::ContentChild* cc =
mozilla::dom::ContentChild::GetSingleton();
if (cc) {
ClonedMessageData data;
SerializedStructuredCloneBuffer& buffer = data.data();
buffer.data = aData.mData;
@ -1153,14 +1161,15 @@ bool SendAsyncMessageToParentProcess(void* aCallbackData,
}
return cc->SendAsyncMessage(nsString(aMessage), data);
}
return true;
}
};
class nsAsyncMessageToSameProcessParent : public nsRunnable
{
public:
nsAsyncMessageToSameProcessParent(const nsAString& aMessage,
const StructuredCloneData& aData)
const StructuredCloneData& aData)
: mMessage(aMessage)
{
if (aData.mDataLength && !mData.copy(aData.mData, aData.mDataLength)) {
@ -1192,19 +1201,57 @@ public:
StructuredCloneClosure mClosure;
};
bool SendAsyncMessageToSameProcessParent(void* aCallbackData,
const nsAString& aMessage,
const StructuredCloneData& aData)
/**
* Send messages to the imaginary parent process in a single-process scenario.
*/
class SameChildProcessMessageManagerCallback : public MessageManagerCallback
{
if (!nsFrameMessageManager::sPendingSameProcessAsyncMessages) {
nsFrameMessageManager::sPendingSameProcessAsyncMessages = new nsTArray<nsCOMPtr<nsIRunnable> >;
public:
SameChildProcessMessageManagerCallback()
{
MOZ_COUNT_CTOR(SameChildProcessMessageManagerCallback);
}
nsCOMPtr<nsIRunnable> ev =
new nsAsyncMessageToSameProcessParent(aMessage, aData);
nsFrameMessageManager::sPendingSameProcessAsyncMessages->AppendElement(ev);
NS_DispatchToCurrentThread(ev);
return true;
}
virtual ~SameChildProcessMessageManagerCallback()
{
MOZ_COUNT_DTOR(SameChildProcessMessageManagerCallback);
}
virtual bool DoSendSyncMessage(const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
InfallibleTArray<nsString>* aJSONRetVal)
{
nsTArray<nsCOMPtr<nsIRunnable> > asyncMessages;
if (nsFrameMessageManager::sPendingSameProcessAsyncMessages) {
asyncMessages.SwapElements(*nsFrameMessageManager::sPendingSameProcessAsyncMessages);
uint32_t len = asyncMessages.Length();
for (uint32_t i = 0; i < len; ++i) {
nsCOMPtr<nsIRunnable> async = asyncMessages[i];
async->Run();
}
}
if (nsFrameMessageManager::sSameProcessParentManager) {
nsRefPtr<nsFrameMessageManager> ppm = nsFrameMessageManager::sSameProcessParentManager;
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), aMessage,
true, &aData, nullptr, aJSONRetVal);
}
return true;
}
virtual bool DoSendAsyncMessage(const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData)
{
if (!nsFrameMessageManager::sPendingSameProcessAsyncMessages) {
nsFrameMessageManager::sPendingSameProcessAsyncMessages = new nsTArray<nsCOMPtr<nsIRunnable> >;
}
nsCOMPtr<nsIRunnable> ev =
new nsAsyncMessageToSameProcessParent(aMessage, aData);
nsFrameMessageManager::sPendingSameProcessAsyncMessages->AppendElement(ev);
NS_DispatchToCurrentThread(ev);
return true;
}
};
// This creates the global parent process message manager.
nsresult
@ -1213,22 +1260,17 @@ NS_NewParentProcessMessageManager(nsIMessageBroadcaster** aResult)
NS_ASSERTION(!nsFrameMessageManager::sParentProcessManager,
"Re-creating sParentProcessManager");
NS_ENSURE_TRUE(IsChromeProcess(), NS_ERROR_NOT_AVAILABLE);
nsRefPtr<nsFrameMessageManager> mm = new nsFrameMessageManager(true /* aChrome */,
nsRefPtr<nsFrameMessageManager> mm = new nsFrameMessageManager(nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
false, /* aGlobal */
true /* aProcessManager */,
true /* aBroadcaster */);
MM_CHROME | MM_PROCESSMANAGER | MM_BROADCASTER);
NS_ENSURE_TRUE(mm, NS_ERROR_OUT_OF_MEMORY);
nsFrameMessageManager::sParentProcessManager = mm;
nsFrameMessageManager::NewProcessMessageManager(nullptr); // Create same process message manager.
return CallQueryInterface(mm, aResult);
}
nsFrameMessageManager*
nsFrameMessageManager::NewProcessMessageManager(mozilla::dom::ContentParent* aProcess)
{
@ -1237,18 +1279,17 @@ nsFrameMessageManager::NewProcessMessageManager(mozilla::dom::ContentParent* aPr
NS_NewParentProcessMessageManager(getter_AddRefs(dummy));
}
nsFrameMessageManager* mm = new nsFrameMessageManager(true /* aChrome */,
nullptr,
aProcess ? SendAsyncMessageToChildProcess
: SendAsyncMessageToSameProcessChild,
nullptr,
aProcess ? static_cast<void*>(aProcess)
: static_cast<void*>(&nsFrameMessageManager::sChildProcessManager),
nsFrameMessageManager::sParentProcessManager,
nullptr,
false, /* aGlobal */
true /* aProcessManager */);
if (!aProcess) {
nsFrameMessageManager* mm;
if (aProcess) {
mm = new nsFrameMessageManager(aProcess,
nsFrameMessageManager::sParentProcessManager,
nullptr,
MM_CHROME | MM_PROCESSMANAGER);
} else {
mm = new nsFrameMessageManager(new SameParentProcessMessageManagerCallback(),
nsFrameMessageManager::sParentProcessManager,
nullptr,
MM_CHROME | MM_PROCESSMANAGER | MM_OWNSCALLBACK);
sSameProcessParentManager = mm;
}
return mm;
@ -1259,18 +1300,17 @@ NS_NewChildProcessMessageManager(nsISyncMessageSender** aResult)
{
NS_ASSERTION(!nsFrameMessageManager::sChildProcessManager,
"Re-creating sChildProcessManager");
bool isChrome = IsChromeProcess();
nsFrameMessageManager* mm = new nsFrameMessageManager(false /* aChrome */,
isChrome ? SendSyncMessageToSameProcessParent
: SendSyncMessageToParentProcess,
isChrome ? SendAsyncMessageToSameProcessParent
: SendAsyncMessageToParentProcess,
nullptr,
&nsFrameMessageManager::sChildProcessManager,
MessageManagerCallback* cb;
if (IsChromeProcess()) {
cb = new SameChildProcessMessageManagerCallback();
} else {
cb = new ChildProcessMessageManagerCallback();
}
nsFrameMessageManager* mm = new nsFrameMessageManager(cb,
nullptr,
nullptr,
false /* aGlobal */,
true /* aProcessManager */);
MM_PROCESSMANAGER | MM_OWNSCALLBACK);
NS_ENSURE_TRUE(mm, NS_ERROR_OUT_OF_MEMORY);
nsFrameMessageManager::sChildProcessManager = mm;
return CallQueryInterface(mm, aResult);

View File

@ -24,10 +24,53 @@
namespace mozilla {
namespace dom {
class ContentParent;
struct StructuredCloneData;
}
}
namespace ipc {
enum MessageManagerFlags {
MM_CHILD = 0,
MM_CHROME = 1,
MM_GLOBAL = 2,
MM_PROCESSMANAGER = 4,
MM_BROADCASTER = 8,
MM_OWNSCALLBACK = 16
};
class MessageManagerCallback
{
public:
virtual ~MessageManagerCallback() {}
virtual bool DoLoadFrameScript(const nsAString& aURL)
{
return true;
}
virtual bool DoSendSyncMessage(const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
InfallibleTArray<nsString>* aJSONRetVal)
{
return true;
}
virtual bool DoSendAsyncMessage(const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData)
{
return true;
}
virtual bool CheckPermission(const nsAString& aPermission)
{
return false;
}
};
} // namespace ipc
} // namespace dom
} // namespace mozilla
class nsAXPCNativeCallContext;
struct JSContext;
@ -39,54 +82,44 @@ struct nsMessageListenerInfo
nsCOMPtr<nsIAtom> mMessage;
};
typedef bool (*nsLoadScriptCallback)(void* aCallbackData, const nsAString& aURL);
typedef bool (*nsSyncMessageCallback)(void* aCallbackData,
const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
InfallibleTArray<nsString>* aJSONRetVal);
typedef bool (*nsAsyncMessageCallback)(void* aCallbackData,
const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData);
class nsFrameMessageManager MOZ_FINAL : public nsIContentFrameMessageManager,
public nsIMessageBroadcaster,
public nsIFrameScriptLoader
public nsIFrameScriptLoader,
public nsIPermissionChecker
{
typedef mozilla::dom::StructuredCloneData StructuredCloneData;
public:
nsFrameMessageManager(bool aChrome,
nsSyncMessageCallback aSyncCallback,
nsAsyncMessageCallback aAsyncCallback,
nsLoadScriptCallback aLoadScriptCallback,
void* aCallbackData,
nsFrameMessageManager(mozilla::dom::ipc::MessageManagerCallback* aCallback,
nsFrameMessageManager* aParentManager,
JSContext* aContext,
bool aGlobal = false,
bool aProcessManager = false,
bool aBroadcaster = false)
: mChrome(aChrome),
mGlobal(aGlobal),
mIsProcessManager(aProcessManager),
mIsBroadcaster(aBroadcaster),
/* mozilla::dom::ipc::MessageManagerFlags */ uint32_t aFlags)
: mChrome(!!(aFlags & mozilla::dom::ipc::MM_CHROME)),
mGlobal(!!(aFlags & mozilla::dom::ipc::MM_GLOBAL)),
mIsProcessManager(!!(aFlags & mozilla::dom::ipc::MM_PROCESSMANAGER)),
mIsBroadcaster(!!(aFlags & mozilla::dom::ipc::MM_BROADCASTER)),
mOwnsCallback(!!(aFlags & mozilla::dom::ipc::MM_OWNSCALLBACK)),
mHandlingMessage(false),
mDisconnected(false),
mCallback(aCallback),
mParentManager(aParentManager),
mSyncCallback(aSyncCallback),
mAsyncCallback(aAsyncCallback),
mLoadScriptCallback(aLoadScriptCallback),
mCallbackData(aCallbackData),
mContext(aContext)
{
NS_ASSERTION(mContext || (aChrome && !aParentManager) || aProcessManager,
NS_ASSERTION(mContext || (mChrome && !mParentManager) || mIsProcessManager,
"Should have mContext in non-global/non-process manager!");
NS_ASSERTION(aChrome || !aParentManager, "Should not set parent manager!");
NS_ASSERTION(mChrome || !aParentManager, "Should not set parent manager!");
NS_ASSERTION(!mIsBroadcaster || !mCallback,
"Broadcasters cannot have callbacks!");
// This is a bit hackish. When parent manager is global, we want
// to attach the window message manager to it immediately.
// Is it just the frame message manager which waits until the
// content process is running.
if (mParentManager && (mCallbackData || IsWindowLevel())) {
if (mParentManager && (mCallback || IsWindowLevel())) {
mParentManager->AddChildManager(this);
}
if (mOwnsCallback) {
mOwnedCallback = aCallback;
}
}
~nsFrameMessageManager()
@ -119,6 +152,7 @@ public:
NS_DECL_NSISYNCMESSAGESENDER
NS_DECL_NSICONTENTFRAMEMESSAGEMANAGER
NS_DECL_NSIFRAMESCRIPTLOADER
NS_DECL_NSIPERMISSIONCHECKER
static nsFrameMessageManager*
NewProcessMessageManager(mozilla::dom::ContentParent* aProcess);
@ -135,19 +169,21 @@ public:
{
mChildManagers.RemoveObject(aManager);
}
void Disconnect(bool aRemoveFromParent = true);
void SetCallbackData(void* aData, bool aLoadScripts = true);
void* GetCallbackData() { return mCallbackData; }
enum ShouldBroadcast { BROADCAST, DONT_BROADCAST };
void SetCallback(mozilla::dom::ipc::MessageManagerCallback* aCallback,
bool aLoadScripts = true);
mozilla::dom::ipc::MessageManagerCallback* GetCallback()
{
return mCallback;
}
nsresult DispatchAsyncMessage(const nsAString& aMessageName,
const jsval& aObject,
JSContext* aCx,
uint8_t aArgc,
ShouldBroadcast aBroadcast);
uint8_t aArgc);
nsresult DispatchAsyncMessageInternal(const nsAString& aMessage,
const StructuredCloneData& aData,
ShouldBroadcast aBroadcast);
const StructuredCloneData& aData);
JSContext* GetJSContext() { return mContext; }
void SetJSContext(JSContext* aCx) { mContext = aCx; }
void RemoveFromParent();
@ -174,16 +210,15 @@ protected:
nsTArray<nsMessageListenerInfo> mListeners;
nsCOMArray<nsIContentFrameMessageManager> mChildManagers;
bool mChrome; // true if we're in the chrome process
bool mGlobal; // true if
bool mGlobal; // true if we're the global frame message manager
bool mIsProcessManager; // true if the message manager belongs to the process realm
bool mIsBroadcaster; // true if the message manager is a broadcaster
bool mOwnsCallback;
bool mHandlingMessage;
bool mDisconnected;
mozilla::dom::ipc::MessageManagerCallback* mCallback;
nsAutoPtr<mozilla::dom::ipc::MessageManagerCallback> mOwnedCallback;
nsFrameMessageManager* mParentManager;
nsSyncMessageCallback mSyncCallback;
nsAsyncMessageCallback mAsyncCallback;
nsLoadScriptCallback mLoadScriptCallback;
void* mCallbackData;
JSContext* mContext;
nsTArray<nsString> mPendingScripts;
public:

View File

@ -25,24 +25,21 @@
using mozilla::dom::StructuredCloneData;
using mozilla::dom::StructuredCloneClosure;
bool SendSyncMessageToParent(void* aCallbackData,
const nsAString& aMessage,
const StructuredCloneData& aData,
InfallibleTArray<nsString>* aJSONRetVal)
bool
nsInProcessTabChildGlobal::DoSendSyncMessage(const nsAString& aMessage,
const StructuredCloneData& aData,
InfallibleTArray<nsString>* aJSONRetVal)
{
nsInProcessTabChildGlobal* tabChild =
static_cast<nsInProcessTabChildGlobal*>(aCallbackData);
nsCOMPtr<nsIContent> owner = tabChild->mOwner;
nsTArray<nsCOMPtr<nsIRunnable> > asyncMessages;
asyncMessages.SwapElements(tabChild->mASyncMessages);
asyncMessages.SwapElements(mASyncMessages);
uint32_t len = asyncMessages.Length();
for (uint32_t i = 0; i < len; ++i) {
nsCOMPtr<nsIRunnable> async = asyncMessages[i];
async->Run();
}
if (tabChild->mChromeMessageManager) {
nsRefPtr<nsFrameMessageManager> mm = tabChild->mChromeMessageManager;
mm->ReceiveMessage(owner, aMessage, true, &aData, nullptr, aJSONRetVal);
if (mChromeMessageManager) {
nsRefPtr<nsFrameMessageManager> mm = mChromeMessageManager;
mm->ReceiveMessage(mOwner, aMessage, true, &aData, nullptr, aJSONRetVal);
}
return true;
}
@ -82,15 +79,13 @@ public:
StructuredCloneClosure mClosure;
};
bool SendAsyncMessageToParent(void* aCallbackData,
const nsAString& aMessage,
const StructuredCloneData& aData)
bool
nsInProcessTabChildGlobal::DoSendAsyncMessage(const nsAString& aMessage,
const StructuredCloneData& aData)
{
nsInProcessTabChildGlobal* tabChild =
static_cast<nsInProcessTabChildGlobal*>(aCallbackData);
nsCOMPtr<nsIRunnable> ev =
new nsAsyncMessageToParent(tabChild, aMessage, aData);
tabChild->mASyncMessages.AppendElement(ev);
new nsAsyncMessageToParent(this, aMessage, aData);
mASyncMessages.AppendElement(ev);
NS_DispatchToCurrentThread(ev);
return true;
}
@ -135,13 +130,10 @@ nsInProcessTabChildGlobal::Init()
InitTabChildGlobal();
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
"Couldn't initialize nsInProcessTabChildGlobal");
mMessageManager = new nsFrameMessageManager(false, /* aChrome */
SendSyncMessageToParent,
SendAsyncMessageToParent,
mMessageManager = new nsFrameMessageManager(this,
nullptr,
this,
nullptr,
mCx);
mCx,
mozilla::dom::ipc::MM_CHILD);
// Set the location information for the new global, so that tools like
// about:memory may use that information.

View File

@ -24,7 +24,8 @@ class nsInProcessTabChildGlobal : public nsDOMEventTargetHelper,
public nsFrameScriptExecutor,
public nsIInProcessContentFrameMessageManager,
public nsIScriptObjectPrincipal,
public nsIScriptContextPrincipal
public nsIScriptContextPrincipal,
public mozilla::dom::ipc::MessageManagerCallback
{
public:
nsInProcessTabChildGlobal(nsIDocShell* aShell, nsIContent* aOwner,
@ -59,6 +60,15 @@ public:
NS_DECL_NSIINPROCESSCONTENTFRAMEMESSAGEMANAGER
/**
* MessageManagerCallback methods that we override.
*/
virtual bool DoSendSyncMessage(const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
InfallibleTArray<nsString>* aJSONRetVal);
virtual bool DoSendAsyncMessage(const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData);
virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
NS_IMETHOD AddEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,

View File

@ -571,6 +571,16 @@ MOCHITEST_FILES_B = \
test_bug789856.html \
$(NULL)
# OOP tests don't work on Windows (bug 763081) or native-fennec
# (see Bug 774939)
ifneq ($(OS_ARCH),WINNT)
ifndef MOZ_JAVA_COMPOSITOR
MOCHITEST_FILES_B += \
test_messagemanager_assertpermission.html \
$(NULL)
endif
endif
MOCHITEST_CHROME_FILES = \
test_bug357450.js \
$(NULL)

View File

@ -0,0 +1,172 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Test for the nsIPermissionChecker part of Message Managers</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body onload="runTests();">
<p id="display">
</p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="application/javascript;version=1.8">
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = SpecialPowers.wrap(Components);
const APP_URL = "http://example.org";
const APP_MANIFEST = "http://example.org/manifest.webapp";
let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"]
.getService(Ci.nsIMessageBroadcaster);
let cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
.getService(Ci.nsISyncMessageSender);
let gAppsService = Cc["@mozilla.org/AppsService;1"]
.getService(Ci.nsIAppsService);
function setUp() {
SpecialPowers.setBoolPref("dom.mozBrowserFramesEnabled", true);
SpecialPowers.setBoolPref("dom.ipc.browser_frames.oop_by_default", true);
SpecialPowers.addPermission("browser", true, window.document);
let appId = gAppsService.getAppLocalIdByManifestURL(APP_MANIFEST);
SpecialPowers.addPermission("foobar", true, { url: APP_URL,
appId: appId,
isInBrowserElement: false });
runNextTest();
}
/**
* Load the example.org app in an <iframe mozbrowser mozapp>
*/
function loadApp(callback) {
let iframe = document.createElement("iframe");
iframe.setAttribute("mozapp", APP_MANIFEST);
iframe.mozbrowser = true;
iframe.src = APP_URL;
document.getElementById("content").appendChild(iframe);
iframe.addEventListener("mozbrowserloadend", function onloadend() {
iframe.removeEventListener("mozbrowserloadend", onloadend);
callback(iframe);
});
}
/**
* Prepare the child process for an intentional crash. This is to keep
* the leak automation tools happy.
*
* This also allows us to acquire the process message manaager that
* corresponds to the process by sending a message to a frame script
* in the content process and having it reply to us via the child
* process message manager.
*/
function prepareProcess(frameMM, callback) {
let frameScript = 'data:,\
privateNoteIntentionalCrash();\
var cpmm = Components.classes["@mozilla.org/childprocessmessagemanager;1"]\
.getService(Components.interfaces.nsISyncMessageSender);\
addMessageListener("TestChild:Ohai", function receiveMessage(msg) {\
cpmm.sendAsyncMessage("TestChild:Ohai");\
});';
frameMM.loadFrameScript(frameScript, false);
frameMM.sendAsyncMessage("TestChild:Ohai");
ppmm.addMessageListener("TestChild:Ohai", function receiveMessage(msg) {
ppmm.removeMessageListener("TestChild:Ohai", receiveMessage);
msg = SpecialPowers.wrap(msg);
callback(msg.target);
});
}
function testSameProcess() {
// Assert permissions on the in-process child process message manager.
// It always has all permissions, including ones that were never
// assigned to anybody.
cpmm.sendAsyncMessage("TestPermission:InProcess");
ppmm.addMessageListener("TestPermission:InProcess", function receiveMessage(msg) {
ppmm.removeMessageListener("TestPermission:InProcess", receiveMessage);
msg = SpecialPowers.wrap(msg);
ok(msg.target.assertPermission("frobnaz"), "in-process cpmm always has all capabilities");
runNextTest();
});
}
function testFrameMessageManager() {
// Assert permissions on the frame message manager.
loadApp(function (iframe) {
let frameMM = SpecialPowers.getBrowserFrameMessageManager(iframe);
prepareProcess(frameMM, function (processMM) {
ok(frameMM.assertPermission("foobar"),
"Frame mm has assigned permission.");
ok(!frameMM.assertPermission("frobnaz"),
"Frame mm doesn't have non-existing permission.");
// The last permission check will result in the content process
// being killed.
iframe.addEventListener("mozbrowsererror", function onerror(event) {
iframe.removeEventListener("mozbrowsererror", onerror);
is(event.detail.type, "fatal", "Observed fatal error event.");
iframe.parentNode.removeChild(iframe);
runNextTest();
});
});
});
}
function testChildProcessMessageManager() {
// Assert permissions on the child process message manager.
loadApp(function (iframe) {
let frameMM = SpecialPowers.getBrowserFrameMessageManager(iframe);
prepareProcess(frameMM, function (processMM) {
ok(processMM.assertPermission("foobar"),
"Process mm has assigned permission.");
ok(!processMM.assertPermission("frobnaz"),
"Process mm doesn't have non-existing permission.");
// The last permission check will result in the content process
// being killed.
iframe.addEventListener("mozbrowsererror", function onerror(event) {
iframe.removeEventListener("mozbrowsererror", onerror);
is(event.detail.type, "fatal", "Observed fatal error event.");
iframe.parentNode.removeChild(iframe);
runNextTest();
});
});
});
}
function tearDown() {
SpecialPowers.clearUserPref("dom.mozBrowserFramesEnabled");
SpecialPowers.clearUserPref("dom.ipc.browser_frames.oop_by_default");
SimpleTest.finish();
}
let _tests = [
setUp,
testSameProcess,
testFrameMessageManager,
testChildProcessMessageManager,
tearDown
]
function runNextTest() {
SimpleTest.executeSoon(_tests.shift());
}
function runTests() {
SimpleTest.waitForExplicitFinish();
runNextTest();
}
</script>
</pre>
</body>
</html>

View File

@ -4350,6 +4350,7 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ChromeMessageSender, nsISupports)
DOM_CLASSINFO_MAP_ENTRY(nsIPermissionChecker)
DOM_CLASSINFO_MAP_ENTRY(nsIFrameScriptLoader)
DOM_CLASSINFO_MAP_ENTRY(nsIMessageListenerManager)
DOM_CLASSINFO_MAP_ENTRY(nsIMessageSender)

View File

@ -235,6 +235,7 @@ static const char kStorageEnabled[] = "dom.storage.enabled";
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::dom::ipc;
using mozilla::TimeStamp;
using mozilla::TimeDuration;
@ -11004,16 +11005,10 @@ nsGlobalChromeWindow::GetMessageManager(nsIMessageBroadcaster** aManager)
nsCOMPtr<nsIMessageBroadcaster> globalMM =
do_GetService("@mozilla.org/globalmessagemanager;1");
mMessageManager =
new nsFrameMessageManager(true, /* aChrome */
nullptr,
nullptr,
nullptr,
nullptr,
new nsFrameMessageManager(nullptr,
static_cast<nsFrameMessageManager*>(globalMM.get()),
cx,
false, /* aGlobal */
false, /* aProcessManager */
true /* aBroadcaster */);
MM_CHROME | MM_BROADCASTER);
NS_ENSURE_TRUE(mMessageManager, NS_ERROR_OUT_OF_MEMORY);
}
CallQueryInterface(mMessageManager, aManager);

View File

@ -1883,5 +1883,37 @@ ContentParent::RecvPrivateDocShellsExist(const bool& aExist)
return true;
}
bool
ContentParent::DoSendAsyncMessage(const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData)
{
ClonedMessageData data;
SerializedStructuredCloneBuffer& buffer = data.data();
buffer.data = aData.mData;
buffer.dataLength = aData.mDataLength;
const nsTArray<nsCOMPtr<nsIDOMBlob> >& blobs = aData.mClosure.mBlobs;
if (!blobs.IsEmpty()) {
InfallibleTArray<PBlobParent*>& blobParents = data.blobsParent();
uint32_t length = blobs.Length();
blobParents.SetCapacity(length);
for (uint32_t i = 0; i < length; ++i) {
BlobParent* blobParent = GetOrCreateActorForBlob(blobs[i]);
if (!blobParent) {
return false;
}
blobParents.AppendElement(blobParent);
}
}
return SendAsyncMessage(nsString(aMessage), data);
}
bool
ContentParent::CheckPermission(const nsAString& aPermission)
{
return AssertAppProcessPermission(this, NS_ConvertUTF16toUTF8(aPermission).get());
}
} // namespace dom
} // namespace mozilla

View File

@ -15,6 +15,7 @@
#include "mozilla/dom/ipc/Blob.h"
#include "mozilla/Attributes.h"
#include "nsFrameMessageManager.h"
#include "nsIObserver.h"
#include "nsIThreadInternal.h"
#include "nsNetUtil.h"
@ -26,7 +27,6 @@
#include "nsHashKeys.h"
class mozIApplication;
class nsFrameMessageManager;
class nsIDOMBlob;
namespace mozilla {
@ -51,6 +51,7 @@ class ContentParent : public PContentParent
, public nsIObserver
, public nsIThreadObserver
, public nsIDOMGeoPositionCallback
, public mozilla::dom::ipc::MessageManagerCallback
{
typedef mozilla::ipc::GeckoChildProcessHost GeckoChildProcessHost;
typedef mozilla::ipc::OptionalURIParams OptionalURIParams;
@ -87,6 +88,13 @@ public:
NS_DECL_NSITHREADOBSERVER
NS_DECL_NSIDOMGEOPOSITIONCALLBACK
/**
* MessageManagerCallback methods that we override.
*/
virtual bool DoSendAsyncMessage(const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData);
virtual bool CheckPermission(const nsAString& aPermission);
/** Notify that a tab was destroyed during normal operation. */
void NotifyTabDestroyed(PBrowserParent* aTab);

View File

@ -75,6 +75,7 @@
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::dom::ipc;
using namespace mozilla::ipc;
using namespace mozilla::layers;
using namespace mozilla::layout;
@ -1458,14 +1459,12 @@ TabChild::DeallocPIndexedDB(PIndexedDBChild* aActor)
return true;
}
static bool
SendSyncMessageToParent(void* aCallbackData,
const nsAString& aMessage,
const StructuredCloneData& aData,
InfallibleTArray<nsString>* aJSONRetVal)
bool
TabChild::DoSendSyncMessage(const nsAString& aMessage,
const StructuredCloneData& aData,
InfallibleTArray<nsString>* aJSONRetVal)
{
TabChild* tabChild = static_cast<TabChild*>(aCallbackData);
ContentChild* cc = static_cast<ContentChild*>(tabChild->Manager());
ContentChild* cc = static_cast<ContentChild*>(Manager());
ClonedMessageData data;
SerializedStructuredCloneBuffer& buffer = data.data();
buffer.data = aData.mData;
@ -1484,16 +1483,14 @@ SendSyncMessageToParent(void* aCallbackData,
blobChildList.AppendElement(blobChild);
}
}
return tabChild->SendSyncMessage(nsString(aMessage), data, aJSONRetVal);
return SendSyncMessage(nsString(aMessage), data, aJSONRetVal);
}
static bool
SendAsyncMessageToParent(void* aCallbackData,
const nsAString& aMessage,
const StructuredCloneData& aData)
bool
TabChild::DoSendAsyncMessage(const nsAString& aMessage,
const StructuredCloneData& aData)
{
TabChild* tabChild = static_cast<TabChild*>(aCallbackData);
ContentChild* cc = static_cast<ContentChild*>(tabChild->Manager());
ContentChild* cc = static_cast<ContentChild*>(Manager());
ClonedMessageData data;
SerializedStructuredCloneBuffer& buffer = data.data();
buffer.data = aData.mData;
@ -1513,7 +1510,7 @@ SendAsyncMessageToParent(void* aCallbackData,
}
}
return tabChild->SendAsyncMessage(nsString(aMessage), data);
return SendAsyncMessage(nsString(aMessage), data);
}
@ -1526,13 +1523,10 @@ void
TabChildGlobal::Init()
{
NS_ASSERTION(!mMessageManager, "Re-initializing?!?");
mMessageManager = new nsFrameMessageManager(false, /* aChrome */
SendSyncMessageToParent,
SendAsyncMessageToParent,
mMessageManager = new nsFrameMessageManager(mTabChild,
nullptr,
mTabChild,
nullptr,
mTabChild->GetJSContext());
mTabChild->GetJSContext(),
MM_CHILD);
}
NS_IMPL_CYCLE_COLLECTION_CLASS(TabChildGlobal)

View File

@ -144,7 +144,8 @@ class TabChild : public PBrowserChild,
public nsSupportsWeakReference,
public nsIDialogCreator,
public nsITabChild,
public nsIObserver
public nsIObserver,
public mozilla::dom::ipc::MessageManagerCallback
{
typedef mozilla::layout::RenderFrameChild RenderFrameChild;
typedef mozilla::dom::ClonedMessageData ClonedMessageData;
@ -178,6 +179,15 @@ public:
NS_DECL_NSITABCHILD
NS_DECL_NSIOBSERVER
/**
* MessageManagerCallback methods that we override.
*/
virtual bool DoSendSyncMessage(const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
InfallibleTArray<nsString>* aJSONRetVal);
virtual bool DoSendAsyncMessage(const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData);
virtual bool RecvLoadURL(const nsCString& uri);
virtual bool RecvShow(const nsIntSize& size);
virtual bool RecvUpdateDimensions(const nsRect& rect, const nsIntSize& size);