1 /* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8; -*- */
2 /* vim: set sw=4 ts=8 et tw=80 : */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsInProcessTabChildGlobal.h"
8 #include "nsContentUtils.h"
9 #include "nsIScriptSecurityManager.h"
10 #include "nsIInterfaceRequestorUtils.h"
11 #include "nsEventDispatcher.h"
12 #include "nsIComponentManager.h"
13 #include "nsIServiceManager.h"
14 #include "nsIJSRuntimeService.h"
15 #include "nsComponentManagerUtils.h"
16 #include "nsNetUtil.h"
17 #include "nsScriptLoader.h"
18 #include "nsFrameLoader.h"
19 #include "xpcpublic.h"
20 #include "nsIMozBrowserFrame.h"
21 #include "nsDOMClassInfoID.h"
22 #include "mozilla/dom/StructuredCloneUtils.h"
23 #include "js/StructuredClone.h"
25 using mozilla::dom::StructuredCloneData
;
26 using mozilla::dom::StructuredCloneClosure
;
29 nsInProcessTabChildGlobal::DoSendBlockingMessage(JSContext
* aCx
,
30 const nsAString
& aMessage
,
31 const mozilla::dom::StructuredCloneData
& aData
,
32 JS::Handle
<JSObject
*> aCpows
,
33 nsIPrincipal
* aPrincipal
,
34 InfallibleTArray
<nsString
>* aJSONRetVal
,
37 nsTArray
<nsCOMPtr
<nsIRunnable
> > asyncMessages
;
38 asyncMessages
.SwapElements(mASyncMessages
);
39 uint32_t len
= asyncMessages
.Length();
40 for (uint32_t i
= 0; i
< len
; ++i
) {
41 nsCOMPtr
<nsIRunnable
> async
= asyncMessages
[i
];
44 if (mChromeMessageManager
) {
45 SameProcessCpowHolder
cpows(js::GetRuntime(aCx
), aCpows
);
46 nsRefPtr
<nsFrameMessageManager
> mm
= mChromeMessageManager
;
47 mm
->ReceiveMessage(mOwner
, aMessage
, true, &aData
, &cpows
, aPrincipal
,
53 class nsAsyncMessageToParent
: public nsRunnable
56 nsAsyncMessageToParent(JSContext
* aCx
,
57 nsInProcessTabChildGlobal
* aTabChild
,
58 const nsAString
& aMessage
,
59 const StructuredCloneData
& aData
,
60 JS::Handle
<JSObject
*> aCpows
,
61 nsIPrincipal
* aPrincipal
)
62 : mRuntime(js::GetRuntime(aCx
)),
66 mPrincipal(aPrincipal
),
69 if (aData
.mDataLength
&& !mData
.copy(aData
.mData
, aData
.mDataLength
)) {
70 NS_RUNTIMEABORT("OOM");
72 if (mCpows
&& !js_AddObjectRoot(mRuntime
, &mCpows
)) {
73 NS_RUNTIMEABORT("OOM");
75 mClosure
= aData
.mClosure
;
78 ~nsAsyncMessageToParent()
81 JS_RemoveObjectRootRT(mRuntime
, &mCpows
);
92 mTabChild
->mASyncMessages
.RemoveElement(this);
93 if (mTabChild
->mChromeMessageManager
) {
94 StructuredCloneData data
;
95 data
.mData
= mData
.data();
96 data
.mDataLength
= mData
.nbytes();
97 data
.mClosure
= mClosure
;
99 SameProcessCpowHolder
cpows(mRuntime
, JS::Handle
<JSObject
*>::fromMarkedLocation(&mCpows
));
101 nsRefPtr
<nsFrameMessageManager
> mm
= mTabChild
->mChromeMessageManager
;
102 mm
->ReceiveMessage(mTabChild
->mOwner
, mMessage
, false, &data
, &cpows
,
103 mPrincipal
, nullptr);
108 nsRefPtr
<nsInProcessTabChildGlobal
> mTabChild
;
110 JSAutoStructuredCloneBuffer mData
;
111 StructuredCloneClosure mClosure
;
113 nsCOMPtr
<nsIPrincipal
> mPrincipal
;
114 // True if this runnable has already been called. This can happen if DoSendSyncMessage
115 // is called while waiting for an asynchronous message send.
120 nsInProcessTabChildGlobal::DoSendAsyncMessage(JSContext
* aCx
,
121 const nsAString
& aMessage
,
122 const StructuredCloneData
& aData
,
123 JS::Handle
<JSObject
*> aCpows
,
124 nsIPrincipal
* aPrincipal
)
126 nsCOMPtr
<nsIRunnable
> ev
=
127 new nsAsyncMessageToParent(aCx
, this, aMessage
, aData
, aCpows
, aPrincipal
);
128 mASyncMessages
.AppendElement(ev
);
129 NS_DispatchToCurrentThread(ev
);
133 nsInProcessTabChildGlobal::nsInProcessTabChildGlobal(nsIDocShell
* aShell
,
135 nsFrameMessageManager
* aChrome
)
136 : mDocShell(aShell
), mInitialized(false), mLoadingScript(false),
137 mDelayedDisconnect(false), mOwner(aOwner
), mChromeMessageManager(aChrome
)
140 // If owner corresponds to an <iframe mozbrowser> or <iframe mozapp>, we'll
141 // have to tweak our PreHandleEvent implementation.
142 nsCOMPtr
<nsIMozBrowserFrame
> browserFrame
= do_QueryInterface(mOwner
);
144 mIsBrowserOrAppFrame
= browserFrame
->GetReallyIsBrowserOrApp();
147 mIsBrowserOrAppFrame
= false;
151 nsInProcessTabChildGlobal::~nsInProcessTabChildGlobal()
155 /* [notxpcom] boolean markForCC (); */
156 // This method isn't automatically forwarded safely because it's notxpcom, so
157 // the IDL binding doesn't know what value to return.
159 nsInProcessTabChildGlobal::MarkForCC()
161 return mMessageManager
? mMessageManager
->MarkForCC() : false;
165 nsInProcessTabChildGlobal::Init()
170 InitTabChildGlobal();
171 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv
),
172 "Couldn't initialize nsInProcessTabChildGlobal");
173 mMessageManager
= new nsFrameMessageManager(this,
175 mozilla::dom::ipc::MM_CHILD
);
179 NS_IMPL_CYCLE_COLLECTION_INHERITED_2(nsInProcessTabChildGlobal
,
180 nsDOMEventTargetHelper
,
184 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsInProcessTabChildGlobal
)
185 NS_INTERFACE_MAP_ENTRY(nsIMessageListenerManager
)
186 NS_INTERFACE_MAP_ENTRY(nsIMessageSender
)
187 NS_INTERFACE_MAP_ENTRY(nsISyncMessageSender
)
188 NS_INTERFACE_MAP_ENTRY(nsIContentFrameMessageManager
)
189 NS_INTERFACE_MAP_ENTRY(nsIInProcessContentFrameMessageManager
)
190 NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal
)
191 NS_INTERFACE_MAP_ENTRY(nsIGlobalObject
)
192 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference
)
193 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ContentFrameMessageManager
)
194 NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper
)
196 NS_IMPL_ADDREF_INHERITED(nsInProcessTabChildGlobal
, nsDOMEventTargetHelper
)
197 NS_IMPL_RELEASE_INHERITED(nsInProcessTabChildGlobal
, nsDOMEventTargetHelper
)
200 nsInProcessTabChildGlobal::GetContent(nsIDOMWindow
** aContent
)
203 nsCOMPtr
<nsIDOMWindow
> window
= do_GetInterface(mDocShell
);
204 window
.swap(*aContent
);
209 nsInProcessTabChildGlobal::GetDocShell(nsIDocShell
** aDocShell
)
211 NS_IF_ADDREF(*aDocShell
= mDocShell
);
216 nsInProcessTabChildGlobal::Btoa(const nsAString
& aBinaryData
,
217 nsAString
& aAsciiBase64String
)
219 return nsContentUtils::Btoa(aBinaryData
, aAsciiBase64String
);
223 nsInProcessTabChildGlobal::Atob(const nsAString
& aAsciiString
,
224 nsAString
& aBinaryData
)
226 return nsContentUtils::Atob(aAsciiString
, aBinaryData
);
231 nsInProcessTabChildGlobal::PrivateNoteIntentionalCrash()
233 return NS_ERROR_NOT_IMPLEMENTED
;
237 nsInProcessTabChildGlobal::Disconnect()
239 // Let the frame scripts know the child is being closed. We do any other
240 // cleanup after the event has been fired. See DelayedDisconnect
241 nsContentUtils::AddScriptRunner(
242 NS_NewRunnableMethod(this, &nsInProcessTabChildGlobal::DelayedDisconnect
)
247 nsInProcessTabChildGlobal::DelayedDisconnect()
249 // Don't let the event escape
252 // Fire the "unload" event
253 nsDOMEventTargetHelper::DispatchTrustedEvent(NS_LITERAL_STRING("unload"));
255 // Continue with the Disconnect cleanup
256 nsCOMPtr
<nsIDOMWindow
> win
= do_GetInterface(mDocShell
);
257 nsCOMPtr
<nsPIDOMWindow
> pwin
= do_QueryInterface(win
);
259 pwin
->SetChromeEventHandler(pwin
->GetChromeEventHandler());
262 mChromeMessageManager
= nullptr;
263 if (mMessageManager
) {
264 static_cast<nsFrameMessageManager
*>(mMessageManager
.get())->Disconnect();
265 mMessageManager
= nullptr;
267 if (mListenerManager
) {
268 mListenerManager
->Disconnect();
271 if (!mLoadingScript
) {
272 ReleaseWrapper(static_cast<EventTarget
*>(this));
275 mDelayedDisconnect
= true;
279 NS_IMETHODIMP_(nsIContent
*)
280 nsInProcessTabChildGlobal::GetOwnerContent()
286 nsInProcessTabChildGlobal::PreHandleEvent(nsEventChainPreVisitor
& aVisitor
)
288 aVisitor
.mCanHandle
= true;
290 if (mIsBrowserOrAppFrame
&&
291 (!mOwner
|| !nsContentUtils::IsInChromeDocshell(mOwner
->OwnerDoc()))) {
293 nsPIDOMWindow
* innerWindow
= mOwner
->OwnerDoc()->GetInnerWindow();
295 aVisitor
.mParentTarget
= innerWindow
->GetParentTarget();
299 aVisitor
.mParentTarget
= mOwner
;
304 nsCOMPtr
<nsIFrameLoaderOwner
> owner
= do_QueryInterface(mOwner
);
305 nsRefPtr
<nsFrameLoader
> fl
= owner
->GetFrameLoader();
307 NS_ASSERTION(this == fl
->GetTabChildGlobalAsEventTarget(),
308 "Wrong event target!");
309 NS_ASSERTION(fl
->mMessageManager
== mChromeMessageManager
,
310 "Wrong message manager!");
319 nsInProcessTabChildGlobal::InitTabChildGlobal()
322 id
.AssignLiteral("inProcessTabChildGlobal");
323 nsIURI
* uri
= mOwner
->OwnerDoc()->GetDocumentURI();
327 id
.AppendLiteral("?ownedBy=");
330 nsISupports
* scopeSupports
= NS_ISUPPORTS_CAST(EventTarget
*, this);
331 NS_ENSURE_STATE(InitTabChildGlobalInternal(scopeSupports
, id
));
335 class nsAsyncScriptLoad
: public nsRunnable
338 nsAsyncScriptLoad(nsInProcessTabChildGlobal
* aTabChild
, const nsAString
& aURL
)
339 : mTabChild(aTabChild
), mURL(aURL
) {}
343 mTabChild
->LoadFrameScript(mURL
);
346 nsRefPtr
<nsInProcessTabChildGlobal
> mTabChild
;
351 nsInProcessTabChildGlobal::LoadFrameScript(const nsAString
& aURL
)
353 if (!nsContentUtils::IsSafeToRunScript()) {
354 nsContentUtils::AddScriptRunner(new nsAsyncScriptLoad(this, aURL
));
361 bool tmp
= mLoadingScript
;
362 mLoadingScript
= true;
363 LoadFrameScriptInternal(aURL
);
364 mLoadingScript
= tmp
;
365 if (!mLoadingScript
&& mDelayedDisconnect
) {
366 mDelayedDisconnect
= false;