/src/mozilla-central/dom/base/InProcessTabChildMessageManager.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 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/. */ |
6 | | |
7 | | #include "InProcessTabChildMessageManager.h" |
8 | | #include "nsContentUtils.h" |
9 | | #include "nsIScriptSecurityManager.h" |
10 | | #include "nsIInterfaceRequestorUtils.h" |
11 | | #include "nsIComponentManager.h" |
12 | | #include "nsIServiceManager.h" |
13 | | #include "nsComponentManagerUtils.h" |
14 | | #include "nsFrameLoader.h" |
15 | | #include "xpcpublic.h" |
16 | | #include "nsIMozBrowserFrame.h" |
17 | | #include "mozilla/EventDispatcher.h" |
18 | | #include "mozilla/dom/ChromeMessageSender.h" |
19 | | #include "mozilla/dom/MessageManagerBinding.h" |
20 | | #include "mozilla/dom/SameProcessMessageQueue.h" |
21 | | #include "mozilla/dom/ScriptLoader.h" |
22 | | |
23 | | using namespace mozilla; |
24 | | using namespace mozilla::dom; |
25 | | using namespace mozilla::dom::ipc; |
26 | | |
27 | | bool |
28 | | InProcessTabChildMessageManager::DoSendBlockingMessage(JSContext* aCx, |
29 | | const nsAString& aMessage, |
30 | | StructuredCloneData& aData, |
31 | | JS::Handle<JSObject *> aCpows, |
32 | | nsIPrincipal* aPrincipal, |
33 | | nsTArray<StructuredCloneData>* aRetVal, |
34 | | bool aIsSync) |
35 | 0 | { |
36 | 0 | SameProcessMessageQueue* queue = SameProcessMessageQueue::Get(); |
37 | 0 | queue->Flush(); |
38 | 0 |
|
39 | 0 | if (mChromeMessageManager) { |
40 | 0 | SameProcessCpowHolder cpows(JS::RootingContext::get(aCx), aCpows); |
41 | 0 | RefPtr<nsFrameMessageManager> mm = mChromeMessageManager; |
42 | 0 | RefPtr<nsFrameLoader> fl = GetFrameLoader(); |
43 | 0 | mm->ReceiveMessage(mOwner, fl, aMessage, true, &aData, &cpows, aPrincipal, |
44 | 0 | aRetVal, IgnoreErrors()); |
45 | 0 | } |
46 | 0 | return true; |
47 | 0 | } |
48 | | |
49 | | class nsAsyncMessageToParent : public nsSameProcessAsyncMessageBase, |
50 | | public SameProcessMessageQueue::Runnable |
51 | | { |
52 | | public: |
53 | | nsAsyncMessageToParent(JS::RootingContext* aRootingCx, |
54 | | JS::Handle<JSObject*> aCpows, |
55 | | InProcessTabChildMessageManager* aTabChild) |
56 | | : nsSameProcessAsyncMessageBase(aRootingCx, aCpows) |
57 | | , mTabChild(aTabChild) |
58 | 0 | { } |
59 | | |
60 | | virtual nsresult HandleMessage() override |
61 | 0 | { |
62 | 0 | RefPtr<nsFrameLoader> fl = mTabChild->GetFrameLoader(); |
63 | 0 | ReceiveMessage(mTabChild->mOwner, fl, mTabChild->mChromeMessageManager); |
64 | 0 | return NS_OK; |
65 | 0 | } |
66 | | RefPtr<InProcessTabChildMessageManager> mTabChild; |
67 | | }; |
68 | | |
69 | | nsresult |
70 | | InProcessTabChildMessageManager::DoSendAsyncMessage(JSContext* aCx, |
71 | | const nsAString& aMessage, |
72 | | StructuredCloneData& aData, |
73 | | JS::Handle<JSObject *> aCpows, |
74 | | nsIPrincipal* aPrincipal) |
75 | 0 | { |
76 | 0 | SameProcessMessageQueue* queue = SameProcessMessageQueue::Get(); |
77 | 0 | JS::RootingContext* rcx = JS::RootingContext::get(aCx); |
78 | 0 | RefPtr<nsAsyncMessageToParent> ev = |
79 | 0 | new nsAsyncMessageToParent(rcx, aCpows, this); |
80 | 0 |
|
81 | 0 | nsresult rv = ev->Init(aMessage, aData, aPrincipal); |
82 | 0 | if (NS_FAILED(rv)) { |
83 | 0 | return rv; |
84 | 0 | } |
85 | 0 | |
86 | 0 | queue->Push(ev); |
87 | 0 | return NS_OK; |
88 | 0 | } |
89 | | |
90 | | InProcessTabChildMessageManager::InProcessTabChildMessageManager(nsIDocShell* aShell, |
91 | | nsIContent* aOwner, |
92 | | nsFrameMessageManager* aChrome) |
93 | | : ContentFrameMessageManager(new nsFrameMessageManager(this)), |
94 | | mDocShell(aShell), mLoadingScript(false), |
95 | | mPreventEventsEscaping(false), |
96 | | mOwner(aOwner), mChromeMessageManager(aChrome) |
97 | 0 | { |
98 | 0 | mozilla::HoldJSObjects(this); |
99 | 0 |
|
100 | 0 | // If owner corresponds to an <iframe mozbrowser>, we'll have to tweak our |
101 | 0 | // GetEventTargetParent implementation. |
102 | 0 | nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwner); |
103 | 0 | if (browserFrame) { |
104 | 0 | mIsBrowserFrame = browserFrame->GetReallyIsBrowser(); |
105 | 0 | } |
106 | 0 | else { |
107 | 0 | mIsBrowserFrame = false; |
108 | 0 | } |
109 | 0 | } |
110 | | |
111 | | InProcessTabChildMessageManager::~InProcessTabChildMessageManager() |
112 | 0 | { |
113 | 0 | mAnonymousGlobalScopes.Clear(); |
114 | 0 | mozilla::DropJSObjects(this); |
115 | 0 | } |
116 | | |
117 | | // This method isn't automatically forwarded safely because it's notxpcom, so |
118 | | // the IDL binding doesn't know what value to return. |
119 | | void |
120 | | InProcessTabChildMessageManager::MarkForCC() |
121 | 0 | { |
122 | 0 | MarkScopesForCC(); |
123 | 0 | MessageManagerGlobal::MarkForCC(); |
124 | 0 | } |
125 | | |
126 | | NS_IMPL_CYCLE_COLLECTION_CLASS(InProcessTabChildMessageManager) |
127 | | |
128 | | |
129 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(InProcessTabChildMessageManager, |
130 | 0 | DOMEventTargetHelper) |
131 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageManager) |
132 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocShell) |
133 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END |
134 | | |
135 | 0 | NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(InProcessTabChildMessageManager, |
136 | 0 | DOMEventTargetHelper) |
137 | 0 | tmp->nsMessageManagerScriptExecutor::Trace(aCallbacks, aClosure); |
138 | 0 | NS_IMPL_CYCLE_COLLECTION_TRACE_END |
139 | | |
140 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(InProcessTabChildMessageManager, |
141 | 0 | DOMEventTargetHelper) |
142 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageManager) |
143 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell) |
144 | 0 | tmp->nsMessageManagerScriptExecutor::Unlink(); |
145 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_END |
146 | | |
147 | 0 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(InProcessTabChildMessageManager) |
148 | 0 | NS_INTERFACE_MAP_ENTRY(nsIMessageSender) |
149 | 0 | NS_INTERFACE_MAP_ENTRY(nsIInProcessContentFrameMessageManager) |
150 | 0 | NS_INTERFACE_MAP_ENTRY(ContentFrameMessageManager) |
151 | 0 | NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) |
152 | 0 | NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) |
153 | | |
154 | | NS_IMPL_ADDREF_INHERITED(InProcessTabChildMessageManager, DOMEventTargetHelper) |
155 | | NS_IMPL_RELEASE_INHERITED(InProcessTabChildMessageManager, DOMEventTargetHelper) |
156 | | |
157 | | JSObject* |
158 | | InProcessTabChildMessageManager::WrapObject(JSContext* aCx, |
159 | | JS::Handle<JSObject*> aGivenProto) |
160 | 0 | { |
161 | 0 | return ContentFrameMessageManager_Binding::Wrap(aCx, this, aGivenProto); |
162 | 0 | } |
163 | | |
164 | | void |
165 | | InProcessTabChildMessageManager::CacheFrameLoader(nsFrameLoader* aFrameLoader) |
166 | 0 | { |
167 | 0 | mFrameLoader = aFrameLoader; |
168 | 0 | } |
169 | | |
170 | | already_AddRefed<nsPIDOMWindowOuter> |
171 | | InProcessTabChildMessageManager::GetContent(ErrorResult& aError) |
172 | 0 | { |
173 | 0 | nsCOMPtr<nsPIDOMWindowOuter> content; |
174 | 0 | if (mDocShell) { |
175 | 0 | content = mDocShell->GetWindow(); |
176 | 0 | } |
177 | 0 | return content.forget(); |
178 | 0 | } |
179 | | |
180 | | already_AddRefed<nsIEventTarget> |
181 | | InProcessTabChildMessageManager::GetTabEventTarget() |
182 | 0 | { |
183 | 0 | nsCOMPtr<nsIEventTarget> target = GetMainThreadEventTarget(); |
184 | 0 | return target.forget(); |
185 | 0 | } |
186 | | |
187 | | uint64_t |
188 | | InProcessTabChildMessageManager::ChromeOuterWindowID() |
189 | 0 | { |
190 | 0 | if (!mDocShell) { |
191 | 0 | return 0; |
192 | 0 | } |
193 | 0 | |
194 | 0 | nsCOMPtr<nsIDocShellTreeItem> item = do_QueryInterface(mDocShell); |
195 | 0 | nsCOMPtr<nsIDocShellTreeItem> root; |
196 | 0 | nsresult rv = item->GetRootTreeItem(getter_AddRefs(root)); |
197 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
198 | 0 | return 0; |
199 | 0 | } |
200 | 0 | |
201 | 0 | nsPIDOMWindowOuter* topWin = root->GetWindow(); |
202 | 0 | if (!topWin) { |
203 | 0 | return 0; |
204 | 0 | } |
205 | 0 | |
206 | 0 | return topWin->WindowID(); |
207 | 0 | } |
208 | | |
209 | | void |
210 | | InProcessTabChildMessageManager::FireUnloadEvent() |
211 | 0 | { |
212 | 0 | // We're called from nsDocument::MaybeInitializeFinalizeFrameLoaders, so it |
213 | 0 | // should be safe to run script. |
214 | 0 | MOZ_ASSERT(nsContentUtils::IsSafeToRunScript()); |
215 | 0 |
|
216 | 0 | // Don't let the unload event propagate to chrome event handlers. |
217 | 0 | mPreventEventsEscaping = true; |
218 | 0 | DOMEventTargetHelper::DispatchTrustedEvent(NS_LITERAL_STRING("unload")); |
219 | 0 |
|
220 | 0 | // Allow events fired during docshell destruction (pagehide, unload) to |
221 | 0 | // propagate to the <browser> element since chrome code depends on this. |
222 | 0 | mPreventEventsEscaping = false; |
223 | 0 | } |
224 | | |
225 | | void |
226 | | InProcessTabChildMessageManager::DisconnectEventListeners() |
227 | 0 | { |
228 | 0 | if (mDocShell) { |
229 | 0 | if (nsCOMPtr<nsPIDOMWindowOuter> win = mDocShell->GetWindow()) { |
230 | 0 | win->SetChromeEventHandler(win->GetChromeEventHandler()); |
231 | 0 | } |
232 | 0 | } |
233 | 0 | if (mListenerManager) { |
234 | 0 | mListenerManager->Disconnect(); |
235 | 0 | } |
236 | 0 |
|
237 | 0 | mDocShell = nullptr; |
238 | 0 | } |
239 | | |
240 | | void |
241 | | InProcessTabChildMessageManager::Disconnect() |
242 | 0 | { |
243 | 0 | mChromeMessageManager = nullptr; |
244 | 0 | mOwner = nullptr; |
245 | 0 | if (mMessageManager) { |
246 | 0 | static_cast<nsFrameMessageManager*>(mMessageManager.get())->Disconnect(); |
247 | 0 | mMessageManager = nullptr; |
248 | 0 | } |
249 | 0 | } |
250 | | |
251 | | NS_IMETHODIMP_(nsIContent *) |
252 | | InProcessTabChildMessageManager::GetOwnerContent() |
253 | 0 | { |
254 | 0 | return mOwner; |
255 | 0 | } |
256 | | |
257 | | void |
258 | | InProcessTabChildMessageManager::GetEventTargetParent(EventChainPreVisitor& aVisitor) |
259 | 0 | { |
260 | 0 | aVisitor.mForceContentDispatch = true; |
261 | 0 | aVisitor.mCanHandle = true; |
262 | 0 |
|
263 | | #ifdef DEBUG |
264 | | if (mOwner) { |
265 | | nsCOMPtr<nsIFrameLoaderOwner> owner = do_QueryInterface(mOwner); |
266 | | RefPtr<nsFrameLoader> fl = owner->GetFrameLoader(); |
267 | | if (fl) { |
268 | | NS_ASSERTION(this == fl->GetTabChildMessageManager(), |
269 | | "Wrong event target!"); |
270 | | NS_ASSERTION(fl->mMessageManager == mChromeMessageManager, |
271 | | "Wrong message manager!"); |
272 | | } |
273 | | } |
274 | | #endif |
275 | |
|
276 | 0 | if (mPreventEventsEscaping) { |
277 | 0 | aVisitor.SetParentTarget(nullptr, false); |
278 | 0 | return; |
279 | 0 | } |
280 | 0 | |
281 | 0 | if (mIsBrowserFrame && |
282 | 0 | (!mOwner || !nsContentUtils::IsInChromeDocshell(mOwner->OwnerDoc()))) { |
283 | 0 | if (mOwner) { |
284 | 0 | if (nsPIDOMWindowInner* innerWindow = mOwner->OwnerDoc()->GetInnerWindow()) { |
285 | 0 | // 'this' is already a "chrome handler", so we consider window's |
286 | 0 | // parent target to be part of that same part of the event path. |
287 | 0 | aVisitor.SetParentTarget(innerWindow->GetParentTarget(), false); |
288 | 0 | } |
289 | 0 | } |
290 | 0 | } else { |
291 | 0 | aVisitor.SetParentTarget(mOwner, false); |
292 | 0 | } |
293 | 0 | } |
294 | | |
295 | | class nsAsyncScriptLoad : public Runnable |
296 | | { |
297 | | public: |
298 | | nsAsyncScriptLoad(InProcessTabChildMessageManager* aTabChild, |
299 | | const nsAString& aURL, |
300 | | bool aRunInGlobalScope) |
301 | | : mozilla::Runnable("nsAsyncScriptLoad") |
302 | | , mTabChild(aTabChild) |
303 | | , mURL(aURL) |
304 | | , mRunInGlobalScope(aRunInGlobalScope) |
305 | 0 | { |
306 | 0 | } |
307 | | |
308 | | NS_IMETHOD Run() override |
309 | 0 | { |
310 | 0 | mTabChild->LoadFrameScript(mURL, mRunInGlobalScope); |
311 | 0 | return NS_OK; |
312 | 0 | } |
313 | | RefPtr<InProcessTabChildMessageManager> mTabChild; |
314 | | nsString mURL; |
315 | | bool mRunInGlobalScope; |
316 | | }; |
317 | | |
318 | | void |
319 | | InProcessTabChildMessageManager::LoadFrameScript(const nsAString& aURL, bool aRunInGlobalScope) |
320 | 0 | { |
321 | 0 | if (!nsContentUtils::IsSafeToRunScript()) { |
322 | 0 | nsContentUtils::AddScriptRunner(new nsAsyncScriptLoad(this, aURL, aRunInGlobalScope)); |
323 | 0 | return; |
324 | 0 | } |
325 | 0 | bool tmp = mLoadingScript; |
326 | 0 | mLoadingScript = true; |
327 | 0 | JS::Rooted<JSObject*> mm(mozilla::dom::RootingCx(), GetOrCreateWrapper()); |
328 | 0 | LoadScriptInternal(mm, aURL, !aRunInGlobalScope); |
329 | 0 | mLoadingScript = tmp; |
330 | 0 | } |
331 | | |
332 | | already_AddRefed<nsFrameLoader> |
333 | | InProcessTabChildMessageManager::GetFrameLoader() |
334 | 0 | { |
335 | 0 | nsCOMPtr<nsIFrameLoaderOwner> owner = do_QueryInterface(mOwner); |
336 | 0 | RefPtr<nsFrameLoader> fl = owner ? owner->GetFrameLoader() : nullptr; |
337 | 0 | if (!fl) { |
338 | 0 | fl = mFrameLoader; |
339 | 0 | } |
340 | 0 | return fl.forget(); |
341 | 0 | } |