Thu, 15 Jan 2015 21:03:48 +0100
Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)
1 /* -*- Mode: C++; c-basic-offset: 2; 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 "nsIComponentManager.h"
12 #include "nsIServiceManager.h"
13 #include "nsIJSRuntimeService.h"
14 #include "nsComponentManagerUtils.h"
15 #include "nsNetUtil.h"
16 #include "nsScriptLoader.h"
17 #include "nsFrameLoader.h"
18 #include "xpcpublic.h"
19 #include "nsIMozBrowserFrame.h"
20 #include "nsDOMClassInfoID.h"
21 #include "mozilla/EventDispatcher.h"
22 #include "mozilla/dom/StructuredCloneUtils.h"
23 #include "js/StructuredClone.h"
25 using mozilla::dom::StructuredCloneData;
26 using mozilla::dom::StructuredCloneClosure;
27 using namespace mozilla;
29 bool
30 nsInProcessTabChildGlobal::DoSendBlockingMessage(JSContext* aCx,
31 const nsAString& aMessage,
32 const dom::StructuredCloneData& aData,
33 JS::Handle<JSObject *> aCpows,
34 nsIPrincipal* aPrincipal,
35 InfallibleTArray<nsString>* aJSONRetVal,
36 bool aIsSync)
37 {
38 nsTArray<nsCOMPtr<nsIRunnable> > asyncMessages;
39 asyncMessages.SwapElements(mASyncMessages);
40 uint32_t len = asyncMessages.Length();
41 for (uint32_t i = 0; i < len; ++i) {
42 nsCOMPtr<nsIRunnable> async = asyncMessages[i];
43 async->Run();
44 }
45 if (mChromeMessageManager) {
46 SameProcessCpowHolder cpows(js::GetRuntime(aCx), aCpows);
47 nsRefPtr<nsFrameMessageManager> mm = mChromeMessageManager;
48 mm->ReceiveMessage(mOwner, aMessage, true, &aData, &cpows, aPrincipal,
49 aJSONRetVal);
50 }
51 return true;
52 }
54 class nsAsyncMessageToParent : public nsSameProcessAsyncMessageBase,
55 public nsRunnable
56 {
57 public:
58 nsAsyncMessageToParent(JSContext* aCx,
59 nsInProcessTabChildGlobal* aTabChild,
60 const nsAString& aMessage,
61 const StructuredCloneData& aData,
62 JS::Handle<JSObject *> aCpows,
63 nsIPrincipal* aPrincipal)
64 : nsSameProcessAsyncMessageBase(aCx, aMessage, aData, aCpows, aPrincipal),
65 mTabChild(aTabChild), mRun(false)
66 {
67 }
69 NS_IMETHOD Run()
70 {
71 if (mRun) {
72 return NS_OK;
73 }
75 mRun = true;
76 mTabChild->mASyncMessages.RemoveElement(this);
77 ReceiveMessage(mTabChild->mOwner, mTabChild->mChromeMessageManager);
78 return NS_OK;
79 }
80 nsRefPtr<nsInProcessTabChildGlobal> mTabChild;
81 // True if this runnable has already been called. This can happen if DoSendSyncMessage
82 // is called while waiting for an asynchronous message send.
83 bool mRun;
84 };
86 bool
87 nsInProcessTabChildGlobal::DoSendAsyncMessage(JSContext* aCx,
88 const nsAString& aMessage,
89 const StructuredCloneData& aData,
90 JS::Handle<JSObject *> aCpows,
91 nsIPrincipal* aPrincipal)
92 {
93 nsCOMPtr<nsIRunnable> ev =
94 new nsAsyncMessageToParent(aCx, this, aMessage, aData, aCpows, aPrincipal);
95 mASyncMessages.AppendElement(ev);
96 NS_DispatchToCurrentThread(ev);
97 return true;
98 }
100 nsInProcessTabChildGlobal::nsInProcessTabChildGlobal(nsIDocShell* aShell,
101 nsIContent* aOwner,
102 nsFrameMessageManager* aChrome)
103 : mDocShell(aShell), mInitialized(false), mLoadingScript(false),
104 mOwner(aOwner), mChromeMessageManager(aChrome)
105 {
107 // If owner corresponds to an <iframe mozbrowser> or <iframe mozapp>, we'll
108 // have to tweak our PreHandleEvent implementation.
109 nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwner);
110 if (browserFrame) {
111 mIsBrowserOrAppFrame = browserFrame->GetReallyIsBrowserOrApp();
112 }
113 else {
114 mIsBrowserOrAppFrame = false;
115 }
116 }
118 nsInProcessTabChildGlobal::~nsInProcessTabChildGlobal()
119 {
120 }
122 /* [notxpcom] boolean markForCC (); */
123 // This method isn't automatically forwarded safely because it's notxpcom, so
124 // the IDL binding doesn't know what value to return.
125 NS_IMETHODIMP_(bool)
126 nsInProcessTabChildGlobal::MarkForCC()
127 {
128 return mMessageManager ? mMessageManager->MarkForCC() : false;
129 }
131 nsresult
132 nsInProcessTabChildGlobal::Init()
133 {
134 #ifdef DEBUG
135 nsresult rv =
136 #endif
137 InitTabChildGlobal();
138 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
139 "Couldn't initialize nsInProcessTabChildGlobal");
140 mMessageManager = new nsFrameMessageManager(this,
141 nullptr,
142 dom::ipc::MM_CHILD);
143 return NS_OK;
144 }
146 NS_IMPL_CYCLE_COLLECTION_INHERITED(nsInProcessTabChildGlobal,
147 DOMEventTargetHelper,
148 mMessageManager,
149 mGlobal)
151 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsInProcessTabChildGlobal)
152 NS_INTERFACE_MAP_ENTRY(nsIMessageListenerManager)
153 NS_INTERFACE_MAP_ENTRY(nsIMessageSender)
154 NS_INTERFACE_MAP_ENTRY(nsISyncMessageSender)
155 NS_INTERFACE_MAP_ENTRY(nsIContentFrameMessageManager)
156 NS_INTERFACE_MAP_ENTRY(nsIInProcessContentFrameMessageManager)
157 NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
158 NS_INTERFACE_MAP_ENTRY(nsIGlobalObject)
159 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
160 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ContentFrameMessageManager)
161 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
163 NS_IMPL_ADDREF_INHERITED(nsInProcessTabChildGlobal, DOMEventTargetHelper)
164 NS_IMPL_RELEASE_INHERITED(nsInProcessTabChildGlobal, DOMEventTargetHelper)
166 NS_IMETHODIMP
167 nsInProcessTabChildGlobal::GetContent(nsIDOMWindow** aContent)
168 {
169 *aContent = nullptr;
170 nsCOMPtr<nsIDOMWindow> window = do_GetInterface(mDocShell);
171 window.swap(*aContent);
172 return NS_OK;
173 }
175 NS_IMETHODIMP
176 nsInProcessTabChildGlobal::GetDocShell(nsIDocShell** aDocShell)
177 {
178 NS_IF_ADDREF(*aDocShell = mDocShell);
179 return NS_OK;
180 }
182 NS_IMETHODIMP
183 nsInProcessTabChildGlobal::Btoa(const nsAString& aBinaryData,
184 nsAString& aAsciiBase64String)
185 {
186 return nsContentUtils::Btoa(aBinaryData, aAsciiBase64String);
187 }
189 NS_IMETHODIMP
190 nsInProcessTabChildGlobal::Atob(const nsAString& aAsciiString,
191 nsAString& aBinaryData)
192 {
193 return nsContentUtils::Atob(aAsciiString, aBinaryData);
194 }
197 NS_IMETHODIMP
198 nsInProcessTabChildGlobal::PrivateNoteIntentionalCrash()
199 {
200 return NS_ERROR_NOT_IMPLEMENTED;
201 }
203 void
204 nsInProcessTabChildGlobal::Disconnect()
205 {
206 // Let the frame scripts know the child is being closed. We do any other
207 // cleanup after the event has been fired. See DelayedDisconnect
208 nsContentUtils::AddScriptRunner(
209 NS_NewRunnableMethod(this, &nsInProcessTabChildGlobal::DelayedDisconnect)
210 );
211 }
213 void
214 nsInProcessTabChildGlobal::DelayedDisconnect()
215 {
216 // Don't let the event escape
217 mOwner = nullptr;
219 // Fire the "unload" event
220 DOMEventTargetHelper::DispatchTrustedEvent(NS_LITERAL_STRING("unload"));
222 // Continue with the Disconnect cleanup
223 nsCOMPtr<nsPIDOMWindow> win = do_GetInterface(mDocShell);
224 if (win) {
225 MOZ_ASSERT(win->IsOuterWindow());
226 win->SetChromeEventHandler(win->GetChromeEventHandler());
227 }
228 mDocShell = nullptr;
229 mChromeMessageManager = nullptr;
230 if (mMessageManager) {
231 static_cast<nsFrameMessageManager*>(mMessageManager.get())->Disconnect();
232 mMessageManager = nullptr;
233 }
234 if (mListenerManager) {
235 mListenerManager->Disconnect();
236 }
237 }
239 NS_IMETHODIMP_(nsIContent *)
240 nsInProcessTabChildGlobal::GetOwnerContent()
241 {
242 return mOwner;
243 }
245 nsresult
246 nsInProcessTabChildGlobal::PreHandleEvent(EventChainPreVisitor& aVisitor)
247 {
248 aVisitor.mCanHandle = true;
250 if (mIsBrowserOrAppFrame &&
251 (!mOwner || !nsContentUtils::IsInChromeDocshell(mOwner->OwnerDoc()))) {
252 if (mOwner) {
253 nsPIDOMWindow* innerWindow = mOwner->OwnerDoc()->GetInnerWindow();
254 if (innerWindow) {
255 aVisitor.mParentTarget = innerWindow->GetParentTarget();
256 }
257 }
258 } else {
259 aVisitor.mParentTarget = mOwner;
260 }
262 #ifdef DEBUG
263 if (mOwner) {
264 nsCOMPtr<nsIFrameLoaderOwner> owner = do_QueryInterface(mOwner);
265 nsRefPtr<nsFrameLoader> fl = owner->GetFrameLoader();
266 if (fl) {
267 NS_ASSERTION(this == fl->GetTabChildGlobalAsEventTarget(),
268 "Wrong event target!");
269 NS_ASSERTION(fl->mMessageManager == mChromeMessageManager,
270 "Wrong message manager!");
271 }
272 }
273 #endif
275 return NS_OK;
276 }
278 nsresult
279 nsInProcessTabChildGlobal::InitTabChildGlobal()
280 {
281 nsAutoCString id;
282 id.AssignLiteral("inProcessTabChildGlobal");
283 nsIURI* uri = mOwner->OwnerDoc()->GetDocumentURI();
284 if (uri) {
285 nsAutoCString u;
286 uri->GetSpec(u);
287 id.AppendLiteral("?ownedBy=");
288 id.Append(u);
289 }
290 nsISupports* scopeSupports = NS_ISUPPORTS_CAST(EventTarget*, this);
291 NS_ENSURE_STATE(InitTabChildGlobalInternal(scopeSupports, id));
292 return NS_OK;
293 }
295 class nsAsyncScriptLoad : public nsRunnable
296 {
297 public:
298 nsAsyncScriptLoad(nsInProcessTabChildGlobal* aTabChild, const nsAString& aURL,
299 bool aRunInGlobalScope)
300 : mTabChild(aTabChild), mURL(aURL), mRunInGlobalScope(aRunInGlobalScope) {}
302 NS_IMETHOD Run()
303 {
304 mTabChild->LoadFrameScript(mURL, mRunInGlobalScope);
305 return NS_OK;
306 }
307 nsRefPtr<nsInProcessTabChildGlobal> mTabChild;
308 nsString mURL;
309 bool mRunInGlobalScope;
310 };
312 void
313 nsInProcessTabChildGlobal::LoadFrameScript(const nsAString& aURL, bool aRunInGlobalScope)
314 {
315 if (!nsContentUtils::IsSafeToRunScript()) {
316 nsContentUtils::AddScriptRunner(new nsAsyncScriptLoad(this, aURL, aRunInGlobalScope));
317 return;
318 }
319 if (!mInitialized) {
320 mInitialized = true;
321 Init();
322 }
323 bool tmp = mLoadingScript;
324 mLoadingScript = true;
325 LoadFrameScriptInternal(aURL, aRunInGlobalScope);
326 mLoadingScript = tmp;
327 }