Line data Source code
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 "base/basictypes.h"
8 :
9 : #include "nsFrameMessageManager.h"
10 :
11 : #include "ContentChild.h"
12 : #include "GeckoProfiler.h"
13 : #include "nsASCIIMask.h"
14 : #include "nsContentUtils.h"
15 : #include "nsDOMClassInfoID.h"
16 : #include "nsError.h"
17 : #include "nsIXPConnect.h"
18 : #include "jsapi.h"
19 : #include "jsfriendapi.h"
20 : #include "nsJSUtils.h"
21 : #include "nsJSPrincipals.h"
22 : #include "nsNetUtil.h"
23 : #include "mozilla/dom/ScriptLoader.h"
24 : #include "nsFrameLoader.h"
25 : #include "nsIInputStream.h"
26 : #include "nsIXULRuntime.h"
27 : #include "nsIScriptError.h"
28 : #include "nsIConsoleService.h"
29 : #include "nsIMemoryReporter.h"
30 : #include "nsIProtocolHandler.h"
31 : #include "nsIScriptSecurityManager.h"
32 : #include "nsIDOMClassInfo.h"
33 : #include "xpcpublic.h"
34 : #include "mozilla/CycleCollectedJSContext.h"
35 : #include "mozilla/IntentionalCrash.h"
36 : #include "mozilla/Preferences.h"
37 : #include "mozilla/ScriptPreloader.h"
38 : #include "mozilla/Telemetry.h"
39 : #include "mozilla/dom/File.h"
40 : #include "mozilla/dom/MessagePort.h"
41 : #include "mozilla/dom/ContentParent.h"
42 : #include "mozilla/dom/PermissionMessageUtils.h"
43 : #include "mozilla/dom/ProcessGlobal.h"
44 : #include "mozilla/dom/SameProcessMessageQueue.h"
45 : #include "mozilla/dom/ScriptSettings.h"
46 : #include "mozilla/dom/ipc/StructuredCloneData.h"
47 : #include "mozilla/dom/DOMStringList.h"
48 : #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
49 : #include "nsPrintfCString.h"
50 : #include "nsXULAppAPI.h"
51 : #include "nsQueryObject.h"
52 : #include <algorithm>
53 : #include "chrome/common/ipc_channel.h" // for IPC::Channel::kMaximumMessageSize
54 :
55 : #ifdef MOZ_CRASHREPORTER
56 : #include "nsExceptionHandler.h"
57 : #endif
58 :
59 : #ifdef ANDROID
60 : #include <android/log.h>
61 : #endif
62 : #ifdef XP_WIN
63 : #include <windows.h>
64 : # if defined(SendMessage)
65 : # undef SendMessage
66 : # endif
67 : #endif
68 :
69 : #ifdef FUZZING
70 : #include "MessageManagerFuzzer.h"
71 : #endif
72 :
73 : using namespace mozilla;
74 : using namespace mozilla::dom;
75 : using namespace mozilla::dom::ipc;
76 :
77 14 : nsFrameMessageManager::nsFrameMessageManager(mozilla::dom::ipc::MessageManagerCallback* aCallback,
78 : nsFrameMessageManager* aParentManager,
79 14 : /* mozilla::dom::ipc::MessageManagerFlags */ uint32_t aFlags)
80 14 : : mChrome(!!(aFlags & mozilla::dom::ipc::MM_CHROME)),
81 14 : mGlobal(!!(aFlags & mozilla::dom::ipc::MM_GLOBAL)),
82 14 : mIsProcessManager(!!(aFlags & mozilla::dom::ipc::MM_PROCESSMANAGER)),
83 14 : mIsBroadcaster(!!(aFlags & mozilla::dom::ipc::MM_BROADCASTER)),
84 14 : mOwnsCallback(!!(aFlags & mozilla::dom::ipc::MM_OWNSCALLBACK)),
85 : mHandlingMessage(false),
86 : mClosed(false),
87 : mDisconnected(false),
88 : mCallback(aCallback),
89 84 : mParentManager(aParentManager)
90 : {
91 14 : NS_ASSERTION(mChrome || !aParentManager, "Should not set parent manager!");
92 14 : NS_ASSERTION(!mIsBroadcaster || !mCallback,
93 : "Broadcasters cannot have callbacks!");
94 14 : if (mIsProcessManager && (!mChrome || IsBroadcaster())) {
95 4 : mozilla::HoldJSObjects(this);
96 : }
97 : // This is a bit hackish. When parent manager is global, we want
98 : // to attach the message manager to it immediately.
99 : // Is it just the frame message manager which waits until the
100 : // content process is running.
101 14 : if (mParentManager && (mCallback || IsBroadcaster())) {
102 3 : mParentManager->AddChildManager(this);
103 : }
104 14 : if (mOwnsCallback) {
105 4 : mOwnedCallback = aCallback;
106 : }
107 14 : }
108 :
109 0 : nsFrameMessageManager::~nsFrameMessageManager()
110 : {
111 0 : if (mIsProcessManager && (!mChrome || IsBroadcaster())) {
112 0 : mozilla::DropJSObjects(this);
113 : }
114 0 : for (int32_t i = mChildManagers.Count(); i > 0; --i) {
115 0 : static_cast<nsFrameMessageManager*>(mChildManagers[i - 1])->
116 0 : Disconnect(false);
117 : }
118 0 : if (mIsProcessManager) {
119 0 : if (this == sParentProcessManager) {
120 0 : sParentProcessManager = nullptr;
121 : }
122 0 : if (this == sChildProcessManager) {
123 0 : sChildProcessManager = nullptr;
124 0 : delete mozilla::dom::SameProcessMessageQueue::Get();
125 : }
126 0 : if (this == sSameProcessParentManager) {
127 0 : sSameProcessParentManager = nullptr;
128 : }
129 : }
130 0 : }
131 :
132 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsFrameMessageManager)
133 :
134 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsFrameMessageManager)
135 0 : for (auto iter = tmp->mListeners.Iter(); !iter.Done(); iter.Next()) {
136 0 : nsAutoTObserverArray<nsMessageListenerInfo, 1>* listeners = iter.UserData();
137 0 : uint32_t count = listeners->Length();
138 0 : for (uint32_t i = 0; i < count; ++i) {
139 0 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "listeners[i] mStrongListener");
140 0 : cb.NoteXPCOMChild(listeners->ElementAt(i).mStrongListener.get());
141 : }
142 : }
143 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildManagers)
144 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentManager)
145 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
146 :
147 2 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsFrameMessageManager)
148 2 : NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mInitialProcessData)
149 2 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
150 :
151 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsFrameMessageManager)
152 0 : tmp->mListeners.Clear();
153 0 : for (int32_t i = tmp->mChildManagers.Count(); i > 0; --i) {
154 0 : static_cast<nsFrameMessageManager*>(tmp->mChildManagers[i - 1])->
155 0 : Disconnect(false);
156 : }
157 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mChildManagers)
158 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mParentManager)
159 0 : tmp->mInitialProcessData.setNull();
160 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
161 :
162 :
163 1270 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFrameMessageManager)
164 1244 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentFrameMessageManager)
165 :
166 : /* nsFrameMessageManager implements nsIMessageSender and nsIMessageBroadcaster,
167 : * both of which descend from nsIMessageListenerManager. QI'ing to
168 : * nsIMessageListenerManager is therefore ambiguous and needs explicit casts
169 : * depending on which child interface applies. */
170 935 : NS_INTERFACE_MAP_ENTRY_AGGREGATED(nsIMessageListenerManager,
171 : (mIsBroadcaster ?
172 : static_cast<nsIMessageListenerManager*>(
173 : static_cast<nsIMessageBroadcaster*>(this)) :
174 : static_cast<nsIMessageListenerManager*>(
175 : static_cast<nsIMessageSender*>(this))))
176 :
177 : /* Message managers in child process implement nsIMessageSender and
178 : nsISyncMessageSender. Message managers in the chrome process are
179 : either broadcasters (if they have subordinate/child message
180 : managers) or they're simple message senders. */
181 884 : NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsISyncMessageSender, !mChrome)
182 884 : NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIMessageSender, !mChrome || !mIsBroadcaster)
183 876 : NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIMessageBroadcaster, mChrome && mIsBroadcaster)
184 :
185 : /* nsIContentFrameMessageManager is accessible only in TabChildGlobal. */
186 850 : NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIContentFrameMessageManager,
187 : !mChrome && !mIsProcessManager)
188 :
189 : /* Frame message managers (non-process message managers) support nsIFrameScriptLoader. */
190 848 : NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIFrameScriptLoader,
191 : mChrome && !mIsProcessManager)
192 :
193 : /* Process message managers (process message managers) support nsIProcessScriptLoader. */
194 837 : NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIProcessScriptLoader,
195 : mChrome && mIsProcessManager)
196 :
197 : /* Global process message managers (process message managers) support nsIGlobalProcessScriptLoader. */
198 828 : NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIGlobalProcessScriptLoader,
199 : mChrome && mIsProcessManager && mIsBroadcaster)
200 :
201 825 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(ChromeMessageBroadcaster,
202 : mChrome && mIsBroadcaster)
203 786 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(ChromeMessageSender,
204 : mChrome && !mIsBroadcaster)
205 775 : NS_INTERFACE_MAP_END
206 :
207 840 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFrameMessageManager)
208 639 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFrameMessageManager)
209 :
210 : bool
211 10 : MessageManagerCallback::BuildClonedMessageDataForParent(nsIContentParent* aParent,
212 : StructuredCloneData& aData,
213 : ClonedMessageData& aClonedData)
214 : {
215 10 : return aData.BuildClonedMessageDataForParent(aParent, aClonedData);
216 : }
217 :
218 : bool
219 34 : MessageManagerCallback::BuildClonedMessageDataForChild(nsIContentChild* aChild,
220 : StructuredCloneData& aData,
221 : ClonedMessageData& aClonedData)
222 : {
223 34 : return aData.BuildClonedMessageDataForChild(aChild, aClonedData);
224 : }
225 :
226 : void
227 32 : mozilla::dom::ipc::UnpackClonedMessageDataForParent(const ClonedMessageData& aClonedData,
228 : StructuredCloneData& aData)
229 : {
230 32 : aData.BorrowFromClonedMessageDataForParent(aClonedData);
231 32 : }
232 :
233 : void
234 10 : mozilla::dom::ipc::UnpackClonedMessageDataForChild(const ClonedMessageData& aClonedData,
235 : StructuredCloneData& aData)
236 : {
237 10 : aData.BorrowFromClonedMessageDataForChild(aClonedData);
238 10 : }
239 :
240 : bool
241 5 : SameProcessCpowHolder::ToObject(JSContext* aCx,
242 : JS::MutableHandle<JSObject*> aObjp)
243 : {
244 5 : if (!mObj) {
245 5 : return true;
246 : }
247 :
248 0 : aObjp.set(mObj);
249 0 : return JS_WrapObject(aCx, aObjp);
250 : }
251 :
252 : // nsIMessageListenerManager
253 :
254 : NS_IMETHODIMP
255 366 : nsFrameMessageManager::AddMessageListener(const nsAString& aMessage,
256 : nsIMessageListener* aListener,
257 : bool aListenWhenClosed)
258 : {
259 1089 : auto listeners = mListeners.LookupForAdd(aMessage).OrInsert([]() {
260 357 : return new nsAutoTObserverArray<nsMessageListenerInfo, 1>();
261 723 : });
262 366 : uint32_t len = listeners->Length();
263 371 : for (uint32_t i = 0; i < len; ++i) {
264 9 : if (listeners->ElementAt(i).mStrongListener == aListener) {
265 4 : return NS_OK;
266 : }
267 : }
268 :
269 362 : nsMessageListenerInfo* entry = listeners->AppendElement();
270 362 : NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);
271 362 : entry->mStrongListener = aListener;
272 362 : entry->mListenWhenClosed = aListenWhenClosed;
273 362 : return NS_OK;
274 : }
275 :
276 : NS_IMETHODIMP
277 7 : nsFrameMessageManager::RemoveMessageListener(const nsAString& aMessage,
278 : nsIMessageListener* aListener)
279 : {
280 : nsAutoTObserverArray<nsMessageListenerInfo, 1>* listeners =
281 7 : mListeners.Get(aMessage);
282 7 : if (!listeners) {
283 0 : return NS_OK;
284 : }
285 :
286 7 : uint32_t len = listeners->Length();
287 7 : for (uint32_t i = 0; i < len; ++i) {
288 7 : if (listeners->ElementAt(i).mStrongListener == aListener) {
289 7 : listeners->RemoveElementAt(i);
290 7 : return NS_OK;
291 : }
292 : }
293 0 : return NS_OK;
294 : }
295 :
296 : NS_IMETHODIMP
297 0 : nsFrameMessageManager::AddWeakMessageListener(const nsAString& aMessage,
298 : nsIMessageListener* aListener)
299 : {
300 0 : nsWeakPtr weak = do_GetWeakReference(aListener);
301 0 : NS_ENSURE_TRUE(weak, NS_ERROR_NO_INTERFACE);
302 :
303 : #ifdef DEBUG
304 : // It's technically possible that one object X could give two different
305 : // nsIWeakReference*'s when you do_GetWeakReference(X). We really don't want
306 : // this to happen; it will break e.g. RemoveWeakMessageListener. So let's
307 : // check that we're not getting ourselves into that situation.
308 0 : nsCOMPtr<nsISupports> canonical = do_QueryInterface(aListener);
309 0 : for (auto iter = mListeners.Iter(); !iter.Done(); iter.Next()) {
310 0 : nsAutoTObserverArray<nsMessageListenerInfo, 1>* listeners = iter.UserData();
311 0 : uint32_t count = listeners->Length();
312 0 : for (uint32_t i = 0; i < count; i++) {
313 0 : nsWeakPtr weakListener = listeners->ElementAt(i).mWeakListener;
314 0 : if (weakListener) {
315 0 : nsCOMPtr<nsISupports> otherCanonical = do_QueryReferent(weakListener);
316 0 : MOZ_ASSERT((canonical == otherCanonical) == (weak == weakListener));
317 : }
318 : }
319 : }
320 : #endif
321 :
322 0 : auto listeners = mListeners.LookupForAdd(aMessage).OrInsert([]() {
323 0 : return new nsAutoTObserverArray<nsMessageListenerInfo, 1>();
324 0 : });
325 0 : uint32_t len = listeners->Length();
326 0 : for (uint32_t i = 0; i < len; ++i) {
327 0 : if (listeners->ElementAt(i).mWeakListener == weak) {
328 0 : return NS_OK;
329 : }
330 : }
331 :
332 0 : nsMessageListenerInfo* entry = listeners->AppendElement();
333 0 : entry->mWeakListener = weak;
334 0 : entry->mListenWhenClosed = false;
335 0 : return NS_OK;
336 : }
337 :
338 : NS_IMETHODIMP
339 0 : nsFrameMessageManager::RemoveWeakMessageListener(const nsAString& aMessage,
340 : nsIMessageListener* aListener)
341 : {
342 0 : nsWeakPtr weak = do_GetWeakReference(aListener);
343 0 : NS_ENSURE_TRUE(weak, NS_OK);
344 :
345 : nsAutoTObserverArray<nsMessageListenerInfo, 1>* listeners =
346 0 : mListeners.Get(aMessage);
347 0 : if (!listeners) {
348 0 : return NS_OK;
349 : }
350 :
351 0 : uint32_t len = listeners->Length();
352 0 : for (uint32_t i = 0; i < len; ++i) {
353 0 : if (listeners->ElementAt(i).mWeakListener == weak) {
354 0 : listeners->RemoveElementAt(i);
355 0 : return NS_OK;
356 : }
357 : }
358 :
359 0 : return NS_OK;
360 : }
361 :
362 : // nsIFrameScriptLoader
363 :
364 : NS_IMETHODIMP
365 77 : nsFrameMessageManager::LoadScript(const nsAString& aURL,
366 : bool aAllowDelayedLoad,
367 : bool aRunInGlobalScope)
368 : {
369 77 : if (aAllowDelayedLoad) {
370 : // Cache for future windows or frames
371 21 : mPendingScripts.AppendElement(aURL);
372 21 : mPendingScriptsGlobalStates.AppendElement(aRunInGlobalScope);
373 : }
374 :
375 77 : if (mCallback) {
376 : #ifdef DEBUG_smaug
377 : printf("Will load %s \n", NS_ConvertUTF16toUTF8(aURL).get());
378 : #endif
379 45 : NS_ENSURE_TRUE(mCallback->DoLoadMessageManagerScript(aURL, aRunInGlobalScope),
380 : NS_ERROR_FAILURE);
381 : }
382 :
383 94 : for (int32_t i = 0; i < mChildManagers.Count(); ++i) {
384 : RefPtr<nsFrameMessageManager> mm =
385 34 : static_cast<nsFrameMessageManager*>(mChildManagers[i]);
386 17 : if (mm) {
387 : // Use false here, so that child managers don't cache the script, which
388 : // is already cached in the parent.
389 17 : mm->LoadScript(aURL, false, aRunInGlobalScope);
390 : }
391 : }
392 77 : return NS_OK;
393 : }
394 :
395 : NS_IMETHODIMP
396 0 : nsFrameMessageManager::RemoveDelayedScript(const nsAString& aURL)
397 : {
398 0 : for (uint32_t i = 0; i < mPendingScripts.Length(); ++i) {
399 0 : if (mPendingScripts[i] == aURL) {
400 0 : mPendingScripts.RemoveElementAt(i);
401 0 : mPendingScriptsGlobalStates.RemoveElementAt(i);
402 0 : break;
403 : }
404 : }
405 0 : return NS_OK;
406 : }
407 :
408 : NS_IMETHODIMP
409 0 : nsFrameMessageManager::GetDelayedScripts(JSContext* aCx, JS::MutableHandle<JS::Value> aList)
410 : {
411 : // Frame message managers may return an incomplete list because scripts
412 : // that were loaded after it was connected are not added to the list.
413 0 : if (!IsGlobal() && !IsBroadcaster()) {
414 : NS_WARNING("Cannot retrieve list of pending frame scripts for frame"
415 0 : "message managers as it may be incomplete");
416 0 : return NS_ERROR_NOT_IMPLEMENTED;
417 : }
418 :
419 0 : JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, mPendingScripts.Length()));
420 0 : NS_ENSURE_TRUE(array, NS_ERROR_OUT_OF_MEMORY);
421 :
422 0 : JS::Rooted<JSString*> url(aCx);
423 0 : JS::Rooted<JSObject*> pair(aCx);
424 0 : for (uint32_t i = 0; i < mPendingScripts.Length(); ++i) {
425 0 : url = JS_NewUCStringCopyN(aCx, mPendingScripts[i].get(), mPendingScripts[i].Length());
426 0 : NS_ENSURE_TRUE(url, NS_ERROR_OUT_OF_MEMORY);
427 :
428 0 : JS::AutoValueArray<2> pairElts(aCx);
429 0 : pairElts[0].setString(url);
430 0 : pairElts[1].setBoolean(mPendingScriptsGlobalStates[i]);
431 :
432 0 : pair = JS_NewArrayObject(aCx, pairElts);
433 0 : NS_ENSURE_TRUE(pair, NS_ERROR_OUT_OF_MEMORY);
434 :
435 0 : NS_ENSURE_TRUE(JS_DefineElement(aCx, array, i, pair, JSPROP_ENUMERATE),
436 : NS_ERROR_OUT_OF_MEMORY);
437 : }
438 :
439 0 : aList.setObject(*array);
440 0 : return NS_OK;
441 : }
442 :
443 : // nsIFrameScriptLoader
444 :
445 : NS_IMETHODIMP
446 51 : nsFrameMessageManager::LoadFrameScript(const nsAString& aURL,
447 : bool aAllowDelayedLoad,
448 : bool aRunInGlobalScope)
449 : {
450 51 : return LoadScript(aURL, aAllowDelayedLoad, aRunInGlobalScope);
451 : }
452 :
453 : NS_IMETHODIMP
454 0 : nsFrameMessageManager::RemoveDelayedFrameScript(const nsAString& aURL)
455 : {
456 0 : return RemoveDelayedScript(aURL);
457 : }
458 :
459 : NS_IMETHODIMP
460 0 : nsFrameMessageManager::GetDelayedFrameScripts(JSContext* aCx, JS::MutableHandle<JS::Value> aList)
461 : {
462 0 : return GetDelayedScripts(aCx, aList);
463 : }
464 :
465 : // nsIProcessScriptLoader
466 :
467 : NS_IMETHODIMP
468 9 : nsFrameMessageManager::LoadProcessScript(const nsAString& aURL,
469 : bool aAllowDelayedLoad)
470 : {
471 9 : return LoadScript(aURL, aAllowDelayedLoad, false);
472 : }
473 :
474 : NS_IMETHODIMP
475 0 : nsFrameMessageManager::RemoveDelayedProcessScript(const nsAString& aURL)
476 : {
477 0 : return RemoveDelayedScript(aURL);
478 : }
479 :
480 : NS_IMETHODIMP
481 0 : nsFrameMessageManager::GetDelayedProcessScripts(JSContext* aCx, JS::MutableHandle<JS::Value> aList)
482 : {
483 0 : return GetDelayedScripts(aCx, aList);
484 : }
485 :
486 : static bool
487 0 : JSONCreator(const char16_t* aBuf, uint32_t aLen, void* aData)
488 : {
489 0 : nsAString* result = static_cast<nsAString*>(aData);
490 : result->Append(static_cast<const char16_t*>(aBuf),
491 0 : static_cast<uint32_t>(aLen));
492 0 : return true;
493 : }
494 :
495 : static bool
496 42 : GetParamsForMessage(JSContext* aCx,
497 : const JS::Value& aValue,
498 : const JS::Value& aTransfer,
499 : StructuredCloneData& aData)
500 : {
501 : // First try to use structured clone on the whole thing.
502 84 : JS::RootedValue v(aCx, aValue);
503 84 : JS::RootedValue t(aCx, aTransfer);
504 84 : ErrorResult rv;
505 42 : aData.Write(aCx, v, t, rv);
506 42 : if (!rv.Failed()) {
507 42 : return true;
508 : }
509 :
510 0 : rv.SuppressException();
511 0 : JS_ClearPendingException(aCx);
512 :
513 0 : nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
514 0 : if (console) {
515 0 : nsAutoString filename;
516 0 : uint32_t lineno = 0, column = 0;
517 0 : nsJSUtils::GetCallingLocation(aCx, filename, &lineno, &column);
518 0 : nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
519 0 : error->Init(NS_LITERAL_STRING("Sending message that cannot be cloned. Are you trying to send an XPCOM object?"),
520 0 : filename, EmptyString(), lineno, column,
521 0 : nsIScriptError::warningFlag, "chrome javascript");
522 0 : console->LogMessage(error);
523 : }
524 :
525 : // Not clonable, try JSON
526 : //XXX This is ugly but currently structured cloning doesn't handle
527 : // properly cases when interface is implemented in JS and used
528 : // as a dictionary.
529 0 : nsAutoString json;
530 0 : NS_ENSURE_TRUE(JS_Stringify(aCx, &v, nullptr, JS::NullHandleValue,
531 : JSONCreator, &json), false);
532 0 : NS_ENSURE_TRUE(!json.IsEmpty(), false);
533 :
534 0 : JS::Rooted<JS::Value> val(aCx, JS::NullValue());
535 0 : NS_ENSURE_TRUE(JS_ParseJSON(aCx, static_cast<const char16_t*>(json.get()),
536 : json.Length(), &val), false);
537 :
538 0 : aData.Write(aCx, val, rv);
539 0 : if (NS_WARN_IF(rv.Failed())) {
540 0 : rv.SuppressException();
541 0 : return false;
542 : }
543 :
544 0 : return true;
545 : }
546 :
547 : // nsISyncMessageSender
548 :
549 : static bool sSendingSyncMessage = false;
550 :
551 : NS_IMETHODIMP
552 0 : nsFrameMessageManager::SendSyncMessage(const nsAString& aMessageName,
553 : JS::Handle<JS::Value> aJSON,
554 : JS::Handle<JS::Value> aObjects,
555 : nsIPrincipal* aPrincipal,
556 : JSContext* aCx,
557 : uint8_t aArgc,
558 : JS::MutableHandle<JS::Value> aRetval)
559 : {
560 0 : return SendMessage(aMessageName, aJSON, aObjects, aPrincipal, aCx, aArgc,
561 0 : aRetval, true);
562 : }
563 :
564 : NS_IMETHODIMP
565 0 : nsFrameMessageManager::SendRpcMessage(const nsAString& aMessageName,
566 : JS::Handle<JS::Value> aJSON,
567 : JS::Handle<JS::Value> aObjects,
568 : nsIPrincipal* aPrincipal,
569 : JSContext* aCx,
570 : uint8_t aArgc,
571 : JS::MutableHandle<JS::Value> aRetval)
572 : {
573 0 : return SendMessage(aMessageName, aJSON, aObjects, aPrincipal, aCx, aArgc,
574 0 : aRetval, false);
575 : }
576 :
577 : static bool
578 48 : AllowMessage(size_t aDataLength, const nsAString& aMessageName)
579 : {
580 : // A message includes more than structured clone data, so subtract
581 : // 20KB to make it more likely that a message within this bound won't
582 : // result in an overly large IPC message.
583 : static const size_t kMaxMessageSize = IPC::Channel::kMaximumMessageSize - 20 * 1024;
584 48 : if (aDataLength < kMaxMessageSize) {
585 48 : return true;
586 : }
587 :
588 0 : NS_ConvertUTF16toUTF8 messageName(aMessageName);
589 0 : messageName.StripTaggedASCII(ASCIIMask::Mask0to9());
590 :
591 : Telemetry::Accumulate(Telemetry::REJECTED_MESSAGE_MANAGER_MESSAGE,
592 0 : messageName);
593 :
594 0 : return false;
595 : }
596 :
597 : nsresult
598 0 : nsFrameMessageManager::SendMessage(const nsAString& aMessageName,
599 : JS::Handle<JS::Value> aJSON,
600 : JS::Handle<JS::Value> aObjects,
601 : nsIPrincipal* aPrincipal,
602 : JSContext* aCx,
603 : uint8_t aArgc,
604 : JS::MutableHandle<JS::Value> aRetval,
605 : bool aIsSync)
606 : {
607 0 : if (profiler_is_active()) {
608 0 : NS_LossyConvertUTF16toASCII messageNameCStr(aMessageName);
609 0 : AUTO_PROFILER_LABEL_DYNAMIC("nsFrameMessageManager::SendMessage", EVENTS,
610 : messageNameCStr.get());
611 : }
612 :
613 0 : NS_ASSERTION(!IsGlobal(), "Should not call SendSyncMessage in chrome");
614 0 : NS_ASSERTION(!IsBroadcaster(), "Should not call SendSyncMessage in chrome");
615 0 : NS_ASSERTION(!mParentManager, "Should not have parent manager in content!");
616 :
617 0 : aRetval.setUndefined();
618 0 : NS_ENSURE_TRUE(mCallback, NS_ERROR_NOT_INITIALIZED);
619 :
620 0 : if (sSendingSyncMessage && aIsSync) {
621 : // No kind of blocking send should be issued on top of a sync message.
622 0 : return NS_ERROR_UNEXPECTED;
623 : }
624 :
625 0 : StructuredCloneData data;
626 0 : if (aArgc >= 2 && !GetParamsForMessage(aCx, aJSON, JS::UndefinedHandleValue, data)) {
627 0 : return NS_ERROR_DOM_DATA_CLONE_ERR;
628 : }
629 :
630 : #ifdef FUZZING
631 : if (data.DataLength() > 0) {
632 : MessageManagerFuzzer::TryMutate(
633 : aCx,
634 : aMessageName,
635 : &data,
636 : JS::UndefinedHandleValue);
637 : }
638 : #endif
639 :
640 0 : if (!AllowMessage(data.DataLength(), aMessageName)) {
641 0 : return NS_ERROR_FAILURE;
642 : }
643 :
644 0 : JS::Rooted<JSObject*> objects(aCx);
645 0 : if (aArgc >= 3 && aObjects.isObject()) {
646 0 : objects = &aObjects.toObject();
647 : }
648 :
649 0 : nsTArray<StructuredCloneData> retval;
650 :
651 0 : TimeStamp start = TimeStamp::Now();
652 0 : sSendingSyncMessage |= aIsSync;
653 0 : bool ok = mCallback->DoSendBlockingMessage(aCx, aMessageName, data, objects,
654 0 : aPrincipal, &retval, aIsSync);
655 0 : if (aIsSync) {
656 0 : sSendingSyncMessage = false;
657 : }
658 :
659 0 : uint32_t latencyMs = round((TimeStamp::Now() - start).ToMilliseconds());
660 0 : if (latencyMs >= kMinTelemetrySyncMessageManagerLatencyMs) {
661 0 : NS_ConvertUTF16toUTF8 messageName(aMessageName);
662 : // NOTE: We need to strip digit characters from the message name in order to
663 : // avoid a large number of buckets due to generated names from addons (such
664 : // as "ublock:sb:{N}"). See bug 1348113 comment 10.
665 0 : messageName.StripTaggedASCII(ASCIIMask::Mask0to9());
666 : Telemetry::Accumulate(Telemetry::IPC_SYNC_MESSAGE_MANAGER_LATENCY_MS,
667 0 : messageName, latencyMs);
668 : }
669 :
670 0 : if (!ok) {
671 0 : return NS_OK;
672 : }
673 :
674 0 : uint32_t len = retval.Length();
675 0 : JS::Rooted<JSObject*> dataArray(aCx, JS_NewArrayObject(aCx, len));
676 0 : NS_ENSURE_TRUE(dataArray, NS_ERROR_OUT_OF_MEMORY);
677 :
678 0 : for (uint32_t i = 0; i < len; ++i) {
679 0 : JS::Rooted<JS::Value> ret(aCx);
680 0 : ErrorResult rv;
681 0 : retval[i].Read(aCx, &ret, rv);
682 0 : if (rv.Failed()) {
683 0 : MOZ_ASSERT(false, "Unable to read structured clone in SendMessage");
684 : rv.SuppressException();
685 : return NS_ERROR_UNEXPECTED;
686 : }
687 :
688 0 : NS_ENSURE_TRUE(JS_DefineElement(aCx, dataArray, i, ret, JSPROP_ENUMERATE),
689 : NS_ERROR_OUT_OF_MEMORY);
690 : }
691 :
692 0 : aRetval.setObject(*dataArray);
693 0 : return NS_OK;
694 : }
695 :
696 : nsresult
697 55 : nsFrameMessageManager::DispatchAsyncMessageInternal(JSContext* aCx,
698 : const nsAString& aMessage,
699 : StructuredCloneData& aData,
700 : JS::Handle<JSObject *> aCpows,
701 : nsIPrincipal* aPrincipal)
702 : {
703 55 : if (mIsBroadcaster) {
704 6 : int32_t len = mChildManagers.Count();
705 13 : for (int32_t i = 0; i < len; ++i) {
706 7 : static_cast<nsFrameMessageManager*>(mChildManagers[i])->
707 7 : DispatchAsyncMessageInternal(aCx, aMessage, aData, aCpows, aPrincipal);
708 : }
709 6 : return NS_OK;
710 : }
711 :
712 49 : if (!mCallback) {
713 0 : return NS_ERROR_NOT_INITIALIZED;
714 : }
715 :
716 49 : nsresult rv = mCallback->DoSendAsyncMessage(aCx, aMessage, aData, aCpows, aPrincipal);
717 49 : if (NS_FAILED(rv)) {
718 0 : return rv;
719 : }
720 49 : return NS_OK;
721 : }
722 :
723 : nsresult
724 48 : nsFrameMessageManager::DispatchAsyncMessage(const nsAString& aMessageName,
725 : const JS::Value& aJSON,
726 : const JS::Value& aObjects,
727 : nsIPrincipal* aPrincipal,
728 : const JS::Value& aTransfers,
729 : JSContext* aCx,
730 : uint8_t aArgc)
731 : {
732 96 : StructuredCloneData data;
733 48 : if (aArgc >= 2 && !GetParamsForMessage(aCx, aJSON, aTransfers, data)) {
734 0 : return NS_ERROR_DOM_DATA_CLONE_ERR;
735 : }
736 :
737 : #ifdef FUZZING
738 : if (data.DataLength()) {
739 : MessageManagerFuzzer::TryMutate(aCx, aMessageName, &data, aTransfers);
740 : }
741 : #endif
742 :
743 48 : if (!AllowMessage(data.DataLength(), aMessageName)) {
744 0 : return NS_ERROR_FAILURE;
745 : }
746 :
747 96 : JS::Rooted<JSObject*> objects(aCx);
748 48 : if (aArgc >= 3 && aObjects.isObject()) {
749 11 : objects = &aObjects.toObject();
750 : }
751 :
752 96 : return DispatchAsyncMessageInternal(aCx, aMessageName, data, objects,
753 48 : aPrincipal);
754 : }
755 :
756 : // nsIMessageSender
757 :
758 : NS_IMETHODIMP
759 44 : nsFrameMessageManager::SendAsyncMessage(const nsAString& aMessageName,
760 : JS::Handle<JS::Value> aJSON,
761 : JS::Handle<JS::Value> aObjects,
762 : nsIPrincipal* aPrincipal,
763 : JS::Handle<JS::Value> aTransfers,
764 : JSContext* aCx,
765 : uint8_t aArgc)
766 : {
767 44 : return DispatchAsyncMessage(aMessageName, aJSON, aObjects, aPrincipal,
768 44 : aTransfers, aCx, aArgc);
769 : }
770 :
771 :
772 : // nsIMessageBroadcaster
773 :
774 : NS_IMETHODIMP
775 4 : nsFrameMessageManager::BroadcastAsyncMessage(const nsAString& aMessageName,
776 : JS::Handle<JS::Value> aJSON,
777 : JS::Handle<JS::Value> aObjects,
778 : JSContext* aCx,
779 : uint8_t aArgc)
780 : {
781 4 : return DispatchAsyncMessage(aMessageName, aJSON, aObjects, nullptr,
782 4 : JS::UndefinedHandleValue, aCx, aArgc);
783 : }
784 :
785 : NS_IMETHODIMP
786 4 : nsFrameMessageManager::GetChildCount(uint32_t* aChildCount)
787 : {
788 4 : *aChildCount = static_cast<uint32_t>(mChildManagers.Count());
789 4 : return NS_OK;
790 : }
791 :
792 : NS_IMETHODIMP
793 4 : nsFrameMessageManager::GetChildAt(uint32_t aIndex,
794 : nsIMessageListenerManager** aMM)
795 : {
796 4 : *aMM = nullptr;
797 : nsCOMPtr<nsIMessageListenerManager> mm =
798 8 : do_QueryInterface(mChildManagers.SafeObjectAt(static_cast<uint32_t>(aIndex)));
799 4 : mm.swap(*aMM);
800 8 : return NS_OK;
801 : }
802 :
803 : NS_IMETHODIMP
804 0 : nsFrameMessageManager::ReleaseCachedProcesses()
805 : {
806 0 : ContentParent::ReleaseCachedProcesses();
807 0 : return NS_OK;
808 : }
809 :
810 : // nsIContentFrameMessageManager
811 :
812 : NS_IMETHODIMP
813 0 : nsFrameMessageManager::Dump(const nsAString& aStr)
814 : {
815 : #ifdef ANDROID
816 : __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", NS_ConvertUTF16toUTF8(aStr).get());
817 : #endif
818 : #ifdef XP_WIN
819 : if (IsDebuggerPresent()) {
820 : OutputDebugStringW(PromiseFlatString(aStr).get());
821 : }
822 : #endif
823 0 : fputs(NS_ConvertUTF16toUTF8(aStr).get(), stdout);
824 0 : fflush(stdout);
825 0 : return NS_OK;
826 : }
827 :
828 : NS_IMETHODIMP
829 0 : nsFrameMessageManager::PrivateNoteIntentionalCrash()
830 : {
831 0 : if (XRE_IsContentProcess()) {
832 0 : mozilla::NoteIntentionalCrash("tab");
833 0 : return NS_OK;
834 : }
835 0 : return NS_ERROR_NOT_IMPLEMENTED;
836 : }
837 :
838 : NS_IMETHODIMP
839 0 : nsFrameMessageManager::GetContent(mozIDOMWindowProxy** aContent)
840 : {
841 0 : *aContent = nullptr;
842 0 : return NS_OK;
843 : }
844 :
845 : NS_IMETHODIMP
846 0 : nsFrameMessageManager::GetDocShell(nsIDocShell** aDocShell)
847 : {
848 0 : *aDocShell = nullptr;
849 0 : return NS_OK;
850 : }
851 :
852 : NS_IMETHODIMP
853 0 : nsFrameMessageManager::Btoa(const nsAString& aBinaryData,
854 : nsAString& aAsciiBase64String)
855 : {
856 0 : return nsContentUtils::Btoa(aBinaryData, aAsciiBase64String);
857 : }
858 :
859 : NS_IMETHODIMP
860 0 : nsFrameMessageManager::Atob(const nsAString& aAsciiString,
861 : nsAString& aBinaryData)
862 : {
863 0 : return nsContentUtils::Atob(aAsciiString, aBinaryData);
864 : }
865 :
866 : class MMListenerRemover
867 : {
868 : public:
869 46 : explicit MMListenerRemover(nsFrameMessageManager* aMM)
870 46 : : mWasHandlingMessage(aMM->mHandlingMessage)
871 46 : , mMM(aMM)
872 : {
873 46 : mMM->mHandlingMessage = true;
874 46 : }
875 45 : ~MMListenerRemover()
876 45 : {
877 45 : if (!mWasHandlingMessage) {
878 45 : mMM->mHandlingMessage = false;
879 45 : if (mMM->mDisconnected) {
880 0 : mMM->mListeners.Clear();
881 : }
882 : }
883 45 : }
884 :
885 : bool mWasHandlingMessage;
886 : RefPtr<nsFrameMessageManager> mMM;
887 : };
888 :
889 :
890 : // nsIMessageListener
891 :
892 : nsresult
893 47 : nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
894 : nsIFrameLoader* aTargetFrameLoader,
895 : const nsAString& aMessage,
896 : bool aIsSync,
897 : StructuredCloneData* aCloneData,
898 : mozilla::jsipc::CpowHolder* aCpows,
899 : nsIPrincipal* aPrincipal,
900 : nsTArray<StructuredCloneData>* aRetVal)
901 : {
902 47 : return ReceiveMessage(aTarget, aTargetFrameLoader, mClosed, aMessage, aIsSync,
903 47 : aCloneData, aCpows, aPrincipal, aRetVal);
904 : }
905 :
906 : nsresult
907 138 : nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
908 : nsIFrameLoader* aTargetFrameLoader,
909 : bool aTargetClosed,
910 : const nsAString& aMessage,
911 : bool aIsSync,
912 : StructuredCloneData* aCloneData,
913 : mozilla::jsipc::CpowHolder* aCpows,
914 : nsIPrincipal* aPrincipal,
915 : nsTArray<StructuredCloneData>* aRetVal)
916 : {
917 : nsAutoTObserverArray<nsMessageListenerInfo, 1>* listeners =
918 138 : mListeners.Get(aMessage);
919 138 : if (listeners) {
920 :
921 91 : MMListenerRemover lr(this);
922 :
923 : nsAutoTObserverArray<nsMessageListenerInfo, 1>::EndLimitedIterator
924 91 : iter(*listeners);
925 136 : while(iter.HasMore()) {
926 46 : nsMessageListenerInfo& listener = iter.GetNext();
927 : // Remove mListeners[i] if it's an expired weak listener.
928 91 : nsCOMPtr<nsISupports> weakListener;
929 46 : if (listener.mWeakListener) {
930 0 : weakListener = do_QueryReferent(listener.mWeakListener);
931 0 : if (!weakListener) {
932 0 : listeners->RemoveElement(listener);
933 0 : continue;
934 : }
935 : }
936 :
937 46 : if (!listener.mListenWhenClosed && aTargetClosed) {
938 0 : continue;
939 : }
940 :
941 91 : nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS;
942 46 : if (weakListener) {
943 0 : wrappedJS = do_QueryInterface(weakListener);
944 : } else {
945 46 : wrappedJS = do_QueryInterface(listener.mStrongListener);
946 : }
947 :
948 46 : if (!wrappedJS) {
949 0 : continue;
950 : }
951 :
952 46 : if (!wrappedJS->GetJSObject()) {
953 0 : continue;
954 : }
955 :
956 91 : AutoEntryScript aes(wrappedJS->GetJSObject(), "message manager handler");
957 46 : JSContext* cx = aes.cx();
958 91 : JS::Rooted<JSObject*> object(cx, wrappedJS->GetJSObject());
959 :
960 : // The parameter for the listener function.
961 91 : JS::Rooted<JSObject*> param(cx, JS_NewPlainObject(cx));
962 46 : NS_ENSURE_TRUE(param, NS_ERROR_OUT_OF_MEMORY);
963 :
964 91 : JS::Rooted<JS::Value> targetv(cx);
965 46 : js::AssertSameCompartment(cx, object);
966 46 : nsresult rv = nsContentUtils::WrapNative(cx, aTarget, &targetv);
967 46 : NS_ENSURE_SUCCESS(rv, rv);
968 :
969 91 : JS::Rooted<JSObject*> cpows(cx);
970 46 : if (aCpows) {
971 46 : if (!aCpows->ToObject(cx, &cpows)) {
972 0 : return NS_ERROR_UNEXPECTED;
973 : }
974 : }
975 :
976 46 : if (!cpows) {
977 35 : cpows = JS_NewPlainObject(cx);
978 35 : if (!cpows) {
979 0 : return NS_ERROR_UNEXPECTED;
980 : }
981 : }
982 :
983 91 : JS::Rooted<JS::Value> cpowsv(cx, JS::ObjectValue(*cpows));
984 :
985 91 : JS::Rooted<JS::Value> json(cx, JS::NullValue());
986 46 : if (aCloneData && aCloneData->DataLength()) {
987 82 : ErrorResult rv;
988 41 : aCloneData->Read(cx, &json, rv);
989 41 : if (NS_WARN_IF(rv.Failed())) {
990 0 : rv.SuppressException();
991 0 : JS_ClearPendingException(cx);
992 0 : return NS_OK;
993 : }
994 : }
995 :
996 : // Get cloned MessagePort from StructuredCloneData.
997 91 : nsTArray<RefPtr<mozilla::dom::MessagePort>> ports;
998 46 : if (aCloneData) {
999 46 : ports = aCloneData->TakeTransferredPorts();
1000 : }
1001 :
1002 91 : JS::Rooted<JS::Value> transferredList(cx);
1003 46 : if (NS_WARN_IF(!ToJSValue(cx, ports, &transferredList))) {
1004 0 : return NS_ERROR_UNEXPECTED;
1005 : }
1006 :
1007 : JS::Rooted<JSString*> jsMessage(cx,
1008 138 : JS_NewUCStringCopyN(cx,
1009 46 : static_cast<const char16_t*>(aMessage.BeginReading()),
1010 137 : aMessage.Length()));
1011 46 : NS_ENSURE_TRUE(jsMessage, NS_ERROR_OUT_OF_MEMORY);
1012 91 : JS::Rooted<JS::Value> syncv(cx, JS::BooleanValue(aIsSync));
1013 368 : bool ok = JS_DefineProperty(cx, param, "target", targetv, JSPROP_ENUMERATE) &&
1014 322 : JS_DefineProperty(cx, param, "name", jsMessage, JSPROP_ENUMERATE) &&
1015 322 : JS_DefineProperty(cx, param, "sync", syncv, JSPROP_ENUMERATE) &&
1016 322 : JS_DefineProperty(cx, param, "json", json, JSPROP_ENUMERATE) && // deprecated
1017 322 : JS_DefineProperty(cx, param, "data", json, JSPROP_ENUMERATE) &&
1018 506 : JS_DefineProperty(cx, param, "objects", cpowsv, JSPROP_ENUMERATE) &&
1019 184 : JS_DefineProperty(cx, param, "ports", transferredList, JSPROP_ENUMERATE);
1020 :
1021 46 : NS_ENSURE_TRUE(ok, NS_ERROR_UNEXPECTED);
1022 :
1023 46 : if (aTargetFrameLoader) {
1024 60 : JS::Rooted<JS::Value> targetFrameLoaderv(cx);
1025 30 : nsresult rv = nsContentUtils::WrapNative(cx, aTargetFrameLoader, &targetFrameLoaderv);
1026 30 : NS_ENSURE_SUCCESS(rv, rv);
1027 :
1028 60 : ok = JS_DefineProperty(cx, param, "targetFrameLoader", targetFrameLoaderv,
1029 30 : JSPROP_ENUMERATE);
1030 30 : NS_ENSURE_TRUE(ok, NS_ERROR_UNEXPECTED);
1031 : }
1032 :
1033 : // message.principal == null
1034 46 : if (!aPrincipal) {
1035 92 : bool ok = JS_DefineProperty(cx, param, "principal",
1036 46 : JS::UndefinedHandleValue, JSPROP_ENUMERATE);
1037 46 : NS_ENSURE_TRUE(ok, NS_ERROR_UNEXPECTED);
1038 : }
1039 :
1040 : // message.principal = the principal
1041 : else {
1042 0 : JS::Rooted<JS::Value> principalValue(cx);
1043 0 : nsresult rv = nsContentUtils::WrapNative(cx, aPrincipal,
1044 : &NS_GET_IID(nsIPrincipal),
1045 0 : &principalValue);
1046 0 : NS_ENSURE_SUCCESS(rv, rv);
1047 0 : bool ok = JS_DefineProperty(cx, param, "principal", principalValue,
1048 0 : JSPROP_ENUMERATE);
1049 0 : NS_ENSURE_TRUE(ok, NS_ERROR_UNEXPECTED);
1050 : }
1051 :
1052 91 : JS::Rooted<JS::Value> thisValue(cx, JS::UndefinedValue());
1053 :
1054 91 : JS::Rooted<JS::Value> funval(cx);
1055 46 : if (JS::IsCallable(object)) {
1056 : // If the listener is a JS function:
1057 25 : funval.setObject(*object);
1058 :
1059 : // A small hack to get 'this' value right on content side where
1060 : // messageManager is wrapped in TabChildGlobal.
1061 50 : nsCOMPtr<nsISupports> defaultThisValue;
1062 25 : if (mChrome) {
1063 13 : defaultThisValue = do_QueryObject(this);
1064 : } else {
1065 12 : defaultThisValue = aTarget;
1066 : }
1067 25 : js::AssertSameCompartment(cx, object);
1068 25 : nsresult rv = nsContentUtils::WrapNative(cx, defaultThisValue, &thisValue);
1069 25 : NS_ENSURE_SUCCESS(rv, rv);
1070 : } else {
1071 : // If the listener is a JS object which has receiveMessage function:
1072 42 : if (!JS_GetProperty(cx, object, "receiveMessage", &funval) ||
1073 21 : !funval.isObject()) {
1074 0 : return NS_ERROR_UNEXPECTED;
1075 : }
1076 :
1077 : // Check if the object is even callable.
1078 21 : NS_ENSURE_STATE(JS::IsCallable(&funval.toObject()));
1079 21 : thisValue.setObject(*object);
1080 : }
1081 :
1082 91 : JS::Rooted<JS::Value> rval(cx, JS::UndefinedValue());
1083 91 : JS::Rooted<JS::Value> argv(cx, JS::ObjectValue(*param));
1084 :
1085 : {
1086 91 : JS::Rooted<JSObject*> thisObject(cx, thisValue.toObjectOrNull());
1087 :
1088 91 : JSAutoCompartment tac(cx, thisObject);
1089 46 : if (!JS_WrapValue(cx, &argv)) {
1090 0 : return NS_ERROR_UNEXPECTED;
1091 : }
1092 :
1093 137 : if (!JS_CallFunctionValue(cx, thisObject, funval,
1094 91 : JS::HandleValueArray(argv), &rval)) {
1095 0 : continue;
1096 : }
1097 45 : if (aRetVal) {
1098 0 : ErrorResult rv;
1099 0 : StructuredCloneData* data = aRetVal->AppendElement();
1100 0 : data->Write(cx, rval, rv);
1101 0 : if (NS_WARN_IF(rv.Failed())) {
1102 0 : aRetVal->RemoveElementAt(aRetVal->Length() - 1);
1103 0 : nsString msg = aMessage + NS_LITERAL_STRING(": message reply cannot be cloned. Are you trying to send an XPCOM object?");
1104 :
1105 0 : nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
1106 0 : if (console) {
1107 0 : nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
1108 0 : error->Init(msg, EmptyString(), EmptyString(),
1109 0 : 0, 0, nsIScriptError::warningFlag, "chrome javascript");
1110 0 : console->LogMessage(error);
1111 : }
1112 :
1113 0 : JS_ClearPendingException(cx);
1114 0 : continue;
1115 : }
1116 : }
1117 : }
1118 : }
1119 : }
1120 :
1121 271 : RefPtr<nsFrameMessageManager> kungFuDeathGrip = mParentManager;
1122 137 : if (kungFuDeathGrip) {
1123 91 : return kungFuDeathGrip->ReceiveMessage(aTarget, aTargetFrameLoader,
1124 : aTargetClosed, aMessage,
1125 : aIsSync, aCloneData,
1126 : aCpows, aPrincipal,
1127 91 : aRetVal);
1128 : }
1129 46 : return NS_OK;
1130 : }
1131 :
1132 : void
1133 7 : nsFrameMessageManager::AddChildManager(nsFrameMessageManager* aManager)
1134 : {
1135 7 : mChildManagers.AppendObject(aManager);
1136 :
1137 14 : RefPtr<nsFrameMessageManager> kungfuDeathGrip = this;
1138 14 : RefPtr<nsFrameMessageManager> kungfuDeathGrip2 = aManager;
1139 :
1140 7 : LoadPendingScripts(this, aManager);
1141 7 : }
1142 :
1143 : void
1144 12 : nsFrameMessageManager::LoadPendingScripts(nsFrameMessageManager* aManager,
1145 : nsFrameMessageManager* aChildMM)
1146 : {
1147 : // We have parent manager if we're a message broadcaster.
1148 : // In that case we want to load the pending scripts from all parent
1149 : // message managers in the hierarchy. Process the parent first so
1150 : // that pending scripts higher up in the hierarchy are loaded before others.
1151 12 : if (aManager->mParentManager) {
1152 5 : LoadPendingScripts(aManager->mParentManager, aChildMM);
1153 : }
1154 :
1155 51 : for (uint32_t i = 0; i < aManager->mPendingScripts.Length(); ++i) {
1156 39 : aChildMM->LoadFrameScript(aManager->mPendingScripts[i],
1157 : false,
1158 78 : aManager->mPendingScriptsGlobalStates[i]);
1159 : }
1160 12 : }
1161 :
1162 : void
1163 0 : nsFrameMessageManager::LoadPendingScripts()
1164 : {
1165 0 : RefPtr<nsFrameMessageManager> kungfuDeathGrip = this;
1166 0 : LoadPendingScripts(this, this);
1167 0 : }
1168 :
1169 : void
1170 4 : nsFrameMessageManager::SetCallback(MessageManagerCallback* aCallback)
1171 : {
1172 4 : MOZ_ASSERT(!mIsBroadcaster || !mCallback,
1173 : "Broadcasters cannot have callbacks!");
1174 4 : if (aCallback && mCallback != aCallback) {
1175 4 : mCallback = aCallback;
1176 4 : if (mOwnsCallback) {
1177 0 : mOwnedCallback = aCallback;
1178 : }
1179 : }
1180 4 : }
1181 :
1182 : void
1183 4 : nsFrameMessageManager::InitWithCallback(MessageManagerCallback* aCallback)
1184 : {
1185 4 : if (mCallback) {
1186 : // Initialization should only happen once.
1187 0 : return;
1188 : }
1189 :
1190 4 : SetCallback(aCallback);
1191 :
1192 : // First load parent scripts by adding this to parent manager.
1193 4 : if (mParentManager) {
1194 4 : mParentManager->AddChildManager(this);
1195 : }
1196 :
1197 4 : for (uint32_t i = 0; i < mPendingScripts.Length(); ++i) {
1198 0 : LoadFrameScript(mPendingScripts[i], false, mPendingScriptsGlobalStates[i]);
1199 : }
1200 : }
1201 :
1202 : void
1203 0 : nsFrameMessageManager::RemoveFromParent()
1204 : {
1205 0 : if (mParentManager) {
1206 0 : mParentManager->RemoveChildManager(this);
1207 : }
1208 0 : mParentManager = nullptr;
1209 0 : mCallback = nullptr;
1210 0 : mOwnedCallback = nullptr;
1211 0 : }
1212 :
1213 : void
1214 3 : nsFrameMessageManager::Close()
1215 : {
1216 3 : if (!mClosed) {
1217 4 : nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
1218 2 : if (obs) {
1219 4 : obs->NotifyObservers(NS_ISUPPORTS_CAST(nsIContentFrameMessageManager*, this),
1220 4 : "message-manager-close", nullptr);
1221 : }
1222 : }
1223 3 : mClosed = true;
1224 3 : mCallback = nullptr;
1225 3 : mOwnedCallback = nullptr;
1226 3 : }
1227 :
1228 : void
1229 2 : nsFrameMessageManager::Disconnect(bool aRemoveFromParent)
1230 : {
1231 : // Notify message-manager-close if we haven't already.
1232 2 : Close();
1233 :
1234 2 : if (!mDisconnected) {
1235 4 : nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
1236 2 : if (obs) {
1237 4 : obs->NotifyObservers(NS_ISUPPORTS_CAST(nsIContentFrameMessageManager*, this),
1238 4 : "message-manager-disconnect", nullptr);
1239 : }
1240 : }
1241 2 : if (mParentManager && aRemoveFromParent) {
1242 1 : mParentManager->RemoveChildManager(this);
1243 : }
1244 2 : mDisconnected = true;
1245 2 : mParentManager = nullptr;
1246 2 : if (!mHandlingMessage) {
1247 2 : mListeners.Clear();
1248 : }
1249 2 : }
1250 :
1251 : void
1252 2 : nsFrameMessageManager::SetInitialProcessData(JS::HandleValue aInitialData)
1253 : {
1254 2 : MOZ_ASSERT(!mChrome);
1255 2 : MOZ_ASSERT(mIsProcessManager);
1256 2 : mInitialProcessData = aInitialData;
1257 2 : }
1258 :
1259 : NS_IMETHODIMP
1260 15 : nsFrameMessageManager::GetInitialProcessData(JSContext* aCx, JS::MutableHandleValue aResult)
1261 : {
1262 15 : MOZ_ASSERT(mIsProcessManager);
1263 15 : MOZ_ASSERT_IF(mChrome, IsBroadcaster());
1264 :
1265 30 : JS::RootedValue init(aCx, mInitialProcessData);
1266 15 : if (mChrome && init.isUndefined()) {
1267 : // We create the initial object in the junk scope. If we created it in a
1268 : // normal compartment, that compartment would leak until shutdown.
1269 2 : JS::RootedObject global(aCx, xpc::PrivilegedJunkScope());
1270 2 : JSAutoCompartment ac(aCx, global);
1271 :
1272 2 : JS::RootedObject obj(aCx, JS_NewPlainObject(aCx));
1273 1 : if (!obj) {
1274 0 : return NS_ERROR_OUT_OF_MEMORY;
1275 : }
1276 :
1277 1 : mInitialProcessData.setObject(*obj);
1278 1 : init.setObject(*obj);
1279 : }
1280 :
1281 15 : if (!mChrome && XRE_IsParentProcess()) {
1282 : // This is the cpmm in the parent process. We should use the same object as the ppmm.
1283 : nsCOMPtr<nsIGlobalProcessScriptLoader> ppmm =
1284 6 : do_GetService("@mozilla.org/parentprocessmessagemanager;1");
1285 3 : ppmm->GetInitialProcessData(aCx, &init);
1286 3 : mInitialProcessData = init;
1287 : }
1288 :
1289 15 : if (!JS_WrapValue(aCx, &init)) {
1290 0 : return NS_ERROR_OUT_OF_MEMORY;
1291 : }
1292 15 : aResult.set(init);
1293 15 : return NS_OK;
1294 : }
1295 :
1296 : NS_IMETHODIMP
1297 0 : nsFrameMessageManager::GetProcessMessageManager(nsIMessageSender** aPMM)
1298 : {
1299 0 : *aPMM = nullptr;
1300 0 : if (mCallback) {
1301 0 : nsCOMPtr<nsIMessageSender> pmm = mCallback->GetProcessMessageManager();
1302 0 : pmm.swap(*aPMM);
1303 : }
1304 0 : return NS_OK;
1305 : }
1306 :
1307 : namespace {
1308 :
1309 0 : struct MessageManagerReferentCount
1310 : {
1311 0 : MessageManagerReferentCount() : mStrong(0), mWeakAlive(0), mWeakDead(0) {}
1312 : size_t mStrong;
1313 : size_t mWeakAlive;
1314 : size_t mWeakDead;
1315 : nsTArray<nsString> mSuspectMessages;
1316 : nsDataHashtable<nsStringHashKey, uint32_t> mMessageCounter;
1317 : };
1318 :
1319 : } // namespace
1320 :
1321 : namespace mozilla {
1322 : namespace dom {
1323 :
1324 3 : class MessageManagerReporter final : public nsIMemoryReporter
1325 : {
1326 : ~MessageManagerReporter() = default;
1327 :
1328 : public:
1329 : NS_DECL_ISUPPORTS
1330 : NS_DECL_NSIMEMORYREPORTER
1331 :
1332 : static const size_t kSuspectReferentCount = 300;
1333 : protected:
1334 : void CountReferents(nsFrameMessageManager* aMessageManager,
1335 : MessageManagerReferentCount* aReferentCount);
1336 : };
1337 :
1338 39 : NS_IMPL_ISUPPORTS(MessageManagerReporter, nsIMemoryReporter)
1339 :
1340 : void
1341 0 : MessageManagerReporter::CountReferents(nsFrameMessageManager* aMessageManager,
1342 : MessageManagerReferentCount* aReferentCount)
1343 : {
1344 0 : for (auto it = aMessageManager->mListeners.Iter(); !it.Done(); it.Next()) {
1345 : nsAutoTObserverArray<nsMessageListenerInfo, 1>* listeners =
1346 0 : it.UserData();
1347 0 : uint32_t listenerCount = listeners->Length();
1348 0 : if (listenerCount == 0) {
1349 0 : continue;
1350 : }
1351 :
1352 0 : nsString key(it.Key());
1353 0 : uint32_t oldCount = 0;
1354 0 : aReferentCount->mMessageCounter.Get(key, &oldCount);
1355 0 : uint32_t currentCount = oldCount + listenerCount;
1356 0 : aReferentCount->mMessageCounter.Put(key, currentCount);
1357 :
1358 : // Keep track of messages that have a suspiciously large
1359 : // number of referents (symptom of leak).
1360 0 : if (currentCount == MessageManagerReporter::kSuspectReferentCount) {
1361 0 : aReferentCount->mSuspectMessages.AppendElement(key);
1362 : }
1363 :
1364 0 : for (uint32_t i = 0; i < listenerCount; ++i) {
1365 0 : const nsMessageListenerInfo& listenerInfo = listeners->ElementAt(i);
1366 0 : if (listenerInfo.mWeakListener) {
1367 : nsCOMPtr<nsISupports> referent =
1368 0 : do_QueryReferent(listenerInfo.mWeakListener);
1369 0 : if (referent) {
1370 0 : aReferentCount->mWeakAlive++;
1371 : } else {
1372 0 : aReferentCount->mWeakDead++;
1373 : }
1374 : } else {
1375 0 : aReferentCount->mStrong++;
1376 : }
1377 : }
1378 : }
1379 :
1380 : // Add referent count in child managers because the listeners
1381 : // participate in messages dispatched from parent message manager.
1382 0 : for (uint32_t i = 0; i < aMessageManager->mChildManagers.Length(); ++i) {
1383 : RefPtr<nsFrameMessageManager> mm =
1384 0 : static_cast<nsFrameMessageManager*>(aMessageManager->mChildManagers[i]);
1385 0 : CountReferents(mm, aReferentCount);
1386 : }
1387 0 : }
1388 :
1389 : static void
1390 0 : ReportReferentCount(const char* aManagerType,
1391 : const MessageManagerReferentCount& aReferentCount,
1392 : nsIHandleReportCallback* aHandleReport,
1393 : nsISupports* aData)
1394 : {
1395 : #define REPORT(_path, _amount, _desc) \
1396 : do { \
1397 : aHandleReport->Callback(EmptyCString(), _path, \
1398 : nsIMemoryReporter::KIND_OTHER, \
1399 : nsIMemoryReporter::UNITS_COUNT, _amount, \
1400 : _desc, aData); \
1401 : } while (0)
1402 :
1403 0 : REPORT(nsPrintfCString("message-manager/referent/%s/strong", aManagerType),
1404 : aReferentCount.mStrong,
1405 : nsPrintfCString("The number of strong referents held by the message "
1406 : "manager in the %s manager.", aManagerType));
1407 0 : REPORT(nsPrintfCString("message-manager/referent/%s/weak/alive", aManagerType),
1408 : aReferentCount.mWeakAlive,
1409 : nsPrintfCString("The number of weak referents that are still alive "
1410 : "held by the message manager in the %s manager.",
1411 : aManagerType));
1412 0 : REPORT(nsPrintfCString("message-manager/referent/%s/weak/dead", aManagerType),
1413 : aReferentCount.mWeakDead,
1414 : nsPrintfCString("The number of weak referents that are dead "
1415 : "held by the message manager in the %s manager.",
1416 : aManagerType));
1417 :
1418 0 : for (uint32_t i = 0; i < aReferentCount.mSuspectMessages.Length(); i++) {
1419 0 : uint32_t totalReferentCount = 0;
1420 0 : aReferentCount.mMessageCounter.Get(aReferentCount.mSuspectMessages[i],
1421 0 : &totalReferentCount);
1422 0 : NS_ConvertUTF16toUTF8 suspect(aReferentCount.mSuspectMessages[i]);
1423 0 : REPORT(nsPrintfCString("message-manager-suspect/%s/referent(message=%s)",
1424 : aManagerType, suspect.get()), totalReferentCount,
1425 : nsPrintfCString("A message in the %s message manager with a "
1426 : "suspiciously large number of referents (symptom "
1427 : "of a leak).", aManagerType));
1428 : }
1429 :
1430 : #undef REPORT
1431 0 : }
1432 :
1433 : NS_IMETHODIMP
1434 0 : MessageManagerReporter::CollectReports(nsIHandleReportCallback* aHandleReport,
1435 : nsISupports* aData, bool aAnonymize)
1436 : {
1437 0 : if (XRE_IsParentProcess()) {
1438 : nsCOMPtr<nsIMessageBroadcaster> globalmm =
1439 0 : do_GetService("@mozilla.org/globalmessagemanager;1");
1440 0 : if (globalmm) {
1441 : RefPtr<nsFrameMessageManager> mm =
1442 0 : static_cast<nsFrameMessageManager*>(globalmm.get());
1443 0 : MessageManagerReferentCount count;
1444 0 : CountReferents(mm, &count);
1445 0 : ReportReferentCount("global-manager", count, aHandleReport, aData);
1446 : }
1447 : }
1448 :
1449 0 : if (nsFrameMessageManager::sParentProcessManager) {
1450 0 : MessageManagerReferentCount count;
1451 0 : CountReferents(nsFrameMessageManager::sParentProcessManager, &count);
1452 0 : ReportReferentCount("parent-process-manager", count, aHandleReport, aData);
1453 : }
1454 :
1455 0 : if (nsFrameMessageManager::sChildProcessManager) {
1456 0 : MessageManagerReferentCount count;
1457 0 : CountReferents(nsFrameMessageManager::sChildProcessManager, &count);
1458 0 : ReportReferentCount("child-process-manager", count, aHandleReport, aData);
1459 : }
1460 :
1461 0 : return NS_OK;
1462 : }
1463 :
1464 : } // namespace dom
1465 : } // namespace mozilla
1466 :
1467 : nsresult
1468 1 : NS_NewGlobalMessageManager(nsIMessageBroadcaster** aResult)
1469 : {
1470 1 : NS_ENSURE_TRUE(XRE_IsParentProcess(),
1471 : NS_ERROR_NOT_AVAILABLE);
1472 : RefPtr<nsFrameMessageManager> mm = new nsFrameMessageManager(nullptr,
1473 : nullptr,
1474 2 : MM_CHROME | MM_GLOBAL | MM_BROADCASTER);
1475 1 : RegisterStrongMemoryReporter(new MessageManagerReporter());
1476 1 : mm.forget(aResult);
1477 1 : return NS_OK;
1478 : }
1479 :
1480 : nsDataHashtable<nsStringHashKey, nsMessageManagerScriptHolder*>*
1481 : nsMessageManagerScriptExecutor::sCachedScripts = nullptr;
1482 3 : StaticRefPtr<nsScriptCacheCleaner> nsMessageManagerScriptExecutor::sScriptCacheCleaner;
1483 :
1484 : void
1485 5 : nsMessageManagerScriptExecutor::DidCreateGlobal()
1486 : {
1487 5 : NS_ASSERTION(mGlobal, "Should have mGlobal!");
1488 5 : if (!sCachedScripts) {
1489 3 : sCachedScripts =
1490 3 : new nsDataHashtable<nsStringHashKey, nsMessageManagerScriptHolder*>;
1491 3 : sScriptCacheCleaner = new nsScriptCacheCleaner();
1492 : }
1493 5 : }
1494 :
1495 : // static
1496 : void
1497 0 : nsMessageManagerScriptExecutor::PurgeCache()
1498 : {
1499 0 : if (sCachedScripts) {
1500 0 : NS_ASSERTION(sCachedScripts != nullptr, "Need cached scripts");
1501 0 : for (auto iter = sCachedScripts->Iter(); !iter.Done(); iter.Next()) {
1502 0 : delete iter.Data();
1503 0 : iter.Remove();
1504 : }
1505 : }
1506 0 : }
1507 :
1508 : // static
1509 : void
1510 0 : nsMessageManagerScriptExecutor::Shutdown()
1511 : {
1512 0 : if (sCachedScripts) {
1513 0 : PurgeCache();
1514 :
1515 0 : delete sCachedScripts;
1516 0 : sCachedScripts = nullptr;
1517 0 : sScriptCacheCleaner = nullptr;
1518 : }
1519 0 : }
1520 :
1521 : void
1522 45 : nsMessageManagerScriptExecutor::LoadScriptInternal(const nsAString& aURL,
1523 : bool aRunInGlobalScope)
1524 : {
1525 45 : if (profiler_is_active()) {
1526 0 : NS_LossyConvertUTF16toASCII urlCStr(aURL);
1527 0 : AUTO_PROFILER_LABEL_DYNAMIC(
1528 : "nsMessageManagerScriptExecutor::LoadScriptInternal", OTHER,
1529 : urlCStr.get());
1530 : }
1531 :
1532 45 : if (!mGlobal || !sCachedScripts) {
1533 0 : return;
1534 : }
1535 :
1536 45 : JS::RootingContext* rcx = RootingCx();
1537 90 : JS::Rooted<JSScript*> script(rcx);
1538 :
1539 45 : nsMessageManagerScriptHolder* holder = sCachedScripts->Get(aURL);
1540 45 : if (holder && holder->WillRunInGlobalScope() == aRunInGlobalScope) {
1541 0 : script = holder->mScript;
1542 : } else {
1543 : // Don't put anything in the cache if we already have an entry
1544 : // with a different WillRunInGlobalScope() value.
1545 45 : bool shouldCache = !holder;
1546 90 : TryCacheLoadAndCompileScript(aURL, aRunInGlobalScope,
1547 45 : shouldCache, &script);
1548 : }
1549 :
1550 90 : JS::Rooted<JSObject*> global(rcx, mGlobal);
1551 45 : if (global) {
1552 90 : AutoEntryScript aes(global, "message manager script load");
1553 45 : JSContext* cx = aes.cx();
1554 45 : if (script) {
1555 45 : if (aRunInGlobalScope) {
1556 0 : JS::RootedValue rval(cx);
1557 0 : JS::CloneAndExecuteScript(cx, script, &rval);
1558 : } else {
1559 90 : JS::Rooted<JSObject*> scope(cx);
1560 45 : bool ok = js::ExecuteInGlobalAndReturnScope(cx, global, script, &scope);
1561 45 : if (ok) {
1562 : // Force the scope to stay alive.
1563 45 : mAnonymousGlobalScopes.AppendElement(scope);
1564 : }
1565 : }
1566 : }
1567 : }
1568 : }
1569 :
1570 : void
1571 45 : nsMessageManagerScriptExecutor::TryCacheLoadAndCompileScript(
1572 : const nsAString& aURL,
1573 : bool aRunInGlobalScope,
1574 : bool aShouldCache,
1575 : JS::MutableHandle<JSScript*> aScriptp)
1576 : {
1577 90 : nsCString url = NS_ConvertUTF16toUTF8(aURL);
1578 90 : nsCOMPtr<nsIURI> uri;
1579 45 : nsresult rv = NS_NewURI(getter_AddRefs(uri), url);
1580 45 : if (NS_FAILED(rv)) {
1581 0 : return;
1582 : }
1583 :
1584 : bool hasFlags;
1585 45 : rv = NS_URIChainHasFlags(uri,
1586 : nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
1587 45 : &hasFlags);
1588 45 : if (NS_FAILED(rv) || !hasFlags) {
1589 0 : NS_WARNING("Will not load a frame script!");
1590 0 : return;
1591 : }
1592 :
1593 : // Compile the script in the compilation scope instead of the current global
1594 : // to avoid keeping the current compartment alive.
1595 90 : AutoJSAPI jsapi;
1596 45 : if (!jsapi.Init(xpc::CompilationScope())) {
1597 0 : return;
1598 : }
1599 45 : JSContext* cx = jsapi.cx();
1600 90 : JS::Rooted<JSScript*> script(cx);
1601 :
1602 45 : script = ScriptPreloader::GetChildSingleton().GetCachedScript(cx, url);
1603 :
1604 45 : if (!script) {
1605 56 : nsCOMPtr<nsIChannel> channel;
1606 56 : NS_NewChannel(getter_AddRefs(channel),
1607 : uri,
1608 : nsContentUtils::GetSystemPrincipal(),
1609 : nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
1610 28 : nsIContentPolicy::TYPE_OTHER);
1611 :
1612 28 : if (!channel) {
1613 0 : return;
1614 : }
1615 :
1616 56 : nsCOMPtr<nsIInputStream> input;
1617 28 : rv = channel->Open2(getter_AddRefs(input));
1618 28 : NS_ENSURE_SUCCESS_VOID(rv);
1619 56 : nsString dataString;
1620 28 : char16_t* dataStringBuf = nullptr;
1621 28 : size_t dataStringLength = 0;
1622 28 : uint64_t avail64 = 0;
1623 28 : if (input && NS_SUCCEEDED(input->Available(&avail64)) && avail64) {
1624 28 : if (avail64 > UINT32_MAX) {
1625 0 : return;
1626 : }
1627 56 : nsCString buffer;
1628 28 : uint32_t avail = (uint32_t)std::min(avail64, (uint64_t)UINT32_MAX);
1629 28 : if (NS_FAILED(NS_ReadInputStreamToString(input, buffer, avail))) {
1630 0 : return;
1631 : }
1632 28 : ScriptLoader::ConvertToUTF16(channel, (uint8_t*)buffer.get(), avail,
1633 28 : EmptyString(), nullptr,
1634 28 : dataStringBuf, dataStringLength);
1635 : }
1636 :
1637 : JS::SourceBufferHolder srcBuf(dataStringBuf, dataStringLength,
1638 56 : JS::SourceBufferHolder::GiveOwnership);
1639 :
1640 28 : if (!dataStringBuf || dataStringLength == 0) {
1641 0 : return;
1642 : }
1643 :
1644 56 : JS::CompileOptions options(cx, JSVERSION_LATEST);
1645 28 : options.setFileAndLine(url.get(), 1);
1646 28 : options.setNoScriptRval(true);
1647 :
1648 28 : if (aRunInGlobalScope) {
1649 0 : if (!JS::Compile(cx, options, srcBuf, &script)) {
1650 0 : return;
1651 : }
1652 : // We're going to run these against some non-global scope.
1653 28 : } else if (!JS::CompileForNonSyntacticScope(cx, options, srcBuf, &script)) {
1654 0 : return;
1655 : }
1656 : }
1657 :
1658 45 : MOZ_ASSERT(script);
1659 45 : aScriptp.set(script);
1660 :
1661 90 : nsAutoCString scheme;
1662 45 : uri->GetScheme(scheme);
1663 : // We don't cache data: scripts!
1664 45 : if (aShouldCache && !scheme.EqualsLiteral("data")) {
1665 39 : ScriptPreloader::GetChildSingleton().NoteScript(url, url, script);
1666 : // Root the object also for caching.
1667 78 : auto* holder = new nsMessageManagerScriptHolder(cx, script, aRunInGlobalScope);
1668 39 : sCachedScripts->Put(aURL, holder);
1669 : }
1670 : }
1671 :
1672 : void
1673 0 : nsMessageManagerScriptExecutor::TryCacheLoadAndCompileScript(
1674 : const nsAString& aURL,
1675 : bool aRunInGlobalScope)
1676 : {
1677 0 : JS::Rooted<JSScript*> script(RootingCx());
1678 0 : TryCacheLoadAndCompileScript(aURL, aRunInGlobalScope, true, &script);
1679 0 : }
1680 :
1681 : void
1682 3 : nsMessageManagerScriptExecutor::Trace(const TraceCallbacks& aCallbacks, void* aClosure)
1683 : {
1684 27 : for (size_t i = 0, length = mAnonymousGlobalScopes.Length(); i < length; ++i) {
1685 24 : aCallbacks.Trace(&mAnonymousGlobalScopes[i], "mAnonymousGlobalScopes[i]", aClosure);
1686 : }
1687 3 : aCallbacks.Trace(&mGlobal, "mGlobal", aClosure);
1688 3 : }
1689 :
1690 : void
1691 0 : nsMessageManagerScriptExecutor::Unlink()
1692 : {
1693 0 : ImplCycleCollectionUnlink(mAnonymousGlobalScopes);
1694 0 : mGlobal = nullptr;
1695 0 : }
1696 :
1697 : bool
1698 5 : nsMessageManagerScriptExecutor::InitChildGlobalInternal(
1699 : nsISupports* aScope,
1700 : const nsACString& aID)
1701 : {
1702 10 : AutoSafeJSContext cx;
1703 5 : nsContentUtils::GetSecurityManager()->GetSystemPrincipal(getter_AddRefs(mPrincipal));
1704 :
1705 5 : nsIXPConnect* xpc = nsContentUtils::XPConnect();
1706 5 : const uint32_t flags = nsIXPConnect::INIT_JS_STANDARD_CLASSES;
1707 :
1708 5 : JS::CompartmentOptions options;
1709 5 : options.creationOptions().setSystemZone();
1710 5 : options.behaviors().setVersion(JSVERSION_LATEST);
1711 :
1712 5 : if (xpc::SharedMemoryEnabled()) {
1713 5 : options.creationOptions().setSharedMemoryAndAtomicsEnabled(true);
1714 : }
1715 :
1716 10 : nsCOMPtr<nsIXPConnectJSObjectHolder> globalHolder;
1717 : nsresult rv =
1718 5 : xpc->InitClassesWithNewWrappedGlobal(cx, aScope, mPrincipal,
1719 : flags, options,
1720 10 : getter_AddRefs(globalHolder));
1721 5 : NS_ENSURE_SUCCESS(rv, false);
1722 :
1723 5 : mGlobal = globalHolder->GetJSObject();
1724 5 : NS_ENSURE_TRUE(mGlobal, false);
1725 :
1726 : // Set the location information for the new global, so that tools like
1727 : // about:memory may use that information.
1728 5 : xpc::SetLocationForGlobal(mGlobal, aID);
1729 :
1730 5 : DidCreateGlobal();
1731 5 : return true;
1732 : }
1733 :
1734 : void
1735 0 : nsMessageManagerScriptExecutor::MarkScopesForCC()
1736 : {
1737 0 : for (uint32_t i = 0; i < mAnonymousGlobalScopes.Length(); ++i) {
1738 0 : mAnonymousGlobalScopes[i].exposeToActiveJS();
1739 : }
1740 0 : }
1741 :
1742 9 : NS_IMPL_ISUPPORTS(nsScriptCacheCleaner, nsIObserver)
1743 :
1744 : nsFrameMessageManager* nsFrameMessageManager::sChildProcessManager = nullptr;
1745 : nsFrameMessageManager* nsFrameMessageManager::sParentProcessManager = nullptr;
1746 : nsFrameMessageManager* nsFrameMessageManager::sSameProcessParentManager = nullptr;
1747 :
1748 12 : class nsAsyncMessageToSameProcessChild : public nsSameProcessAsyncMessageBase,
1749 : public Runnable
1750 : {
1751 : public:
1752 4 : nsAsyncMessageToSameProcessChild(JS::RootingContext* aRootingCx,
1753 : JS::Handle<JSObject*> aCpows)
1754 4 : : nsSameProcessAsyncMessageBase(aRootingCx, aCpows)
1755 4 : , mozilla::Runnable("nsAsyncMessageToSameProcessChild")
1756 4 : { }
1757 4 : NS_IMETHOD Run() override
1758 : {
1759 4 : nsFrameMessageManager* ppm = nsFrameMessageManager::GetChildProcessManager();
1760 4 : ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm), nullptr, ppm);
1761 4 : return NS_OK;
1762 : }
1763 : };
1764 :
1765 :
1766 : /**
1767 : * Send messages to an imaginary child process in a single-process scenario.
1768 : */
1769 : class SameParentProcessMessageManagerCallback : public MessageManagerCallback
1770 : {
1771 : public:
1772 1 : SameParentProcessMessageManagerCallback()
1773 1 : {
1774 1 : MOZ_COUNT_CTOR(SameParentProcessMessageManagerCallback);
1775 1 : }
1776 0 : ~SameParentProcessMessageManagerCallback() override
1777 0 : {
1778 0 : MOZ_COUNT_DTOR(SameParentProcessMessageManagerCallback);
1779 0 : }
1780 :
1781 9 : bool DoLoadMessageManagerScript(const nsAString& aURL,
1782 : bool aRunInGlobalScope) override
1783 : {
1784 9 : ProcessGlobal* global = ProcessGlobal::Get();
1785 9 : MOZ_ASSERT(!aRunInGlobalScope);
1786 9 : global->LoadScript(aURL);
1787 9 : return true;
1788 : }
1789 :
1790 4 : nsresult DoSendAsyncMessage(JSContext* aCx,
1791 : const nsAString& aMessage,
1792 : StructuredCloneData& aData,
1793 : JS::Handle<JSObject *> aCpows,
1794 : nsIPrincipal* aPrincipal) override
1795 : {
1796 4 : JS::RootingContext* rcx = JS::RootingContext::get(aCx);
1797 : RefPtr<nsAsyncMessageToSameProcessChild> ev =
1798 12 : new nsAsyncMessageToSameProcessChild(rcx, aCpows);
1799 :
1800 4 : nsresult rv = ev->Init(aMessage, aData, aPrincipal);
1801 4 : if (NS_FAILED(rv)) {
1802 0 : return rv;
1803 : }
1804 4 : rv = NS_DispatchToCurrentThread(ev);
1805 4 : if (NS_FAILED(rv)) {
1806 0 : return rv;
1807 : }
1808 4 : return NS_OK;
1809 : }
1810 : };
1811 :
1812 :
1813 : /**
1814 : * Send messages to the parent process.
1815 : */
1816 : class ChildProcessMessageManagerCallback : public MessageManagerCallback
1817 : {
1818 : public:
1819 2 : ChildProcessMessageManagerCallback()
1820 2 : {
1821 2 : MOZ_COUNT_CTOR(ChildProcessMessageManagerCallback);
1822 2 : }
1823 0 : ~ChildProcessMessageManagerCallback() override
1824 0 : {
1825 0 : MOZ_COUNT_DTOR(ChildProcessMessageManagerCallback);
1826 0 : }
1827 :
1828 0 : bool DoSendBlockingMessage(JSContext* aCx,
1829 : const nsAString& aMessage,
1830 : StructuredCloneData& aData,
1831 : JS::Handle<JSObject *> aCpows,
1832 : nsIPrincipal* aPrincipal,
1833 : nsTArray<StructuredCloneData>* aRetVal,
1834 : bool aIsSync) override
1835 : {
1836 : mozilla::dom::ContentChild* cc =
1837 0 : mozilla::dom::ContentChild::GetSingleton();
1838 0 : if (!cc) {
1839 0 : return true;
1840 : }
1841 0 : ClonedMessageData data;
1842 0 : if (!BuildClonedMessageDataForChild(cc, aData, data)) {
1843 0 : return false;
1844 : }
1845 0 : InfallibleTArray<mozilla::jsipc::CpowEntry> cpows;
1846 0 : if (aCpows && !cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
1847 0 : return false;
1848 : }
1849 0 : if (aIsSync) {
1850 0 : return cc->SendSyncMessage(PromiseFlatString(aMessage), data, cpows,
1851 0 : IPC::Principal(aPrincipal), aRetVal);
1852 : }
1853 0 : return cc->SendRpcMessage(PromiseFlatString(aMessage), data, cpows,
1854 0 : IPC::Principal(aPrincipal), aRetVal);
1855 : }
1856 :
1857 4 : nsresult DoSendAsyncMessage(JSContext* aCx,
1858 : const nsAString& aMessage,
1859 : StructuredCloneData& aData,
1860 : JS::Handle<JSObject *> aCpows,
1861 : nsIPrincipal* aPrincipal) override
1862 : {
1863 : mozilla::dom::ContentChild* cc =
1864 4 : mozilla::dom::ContentChild::GetSingleton();
1865 4 : if (!cc) {
1866 0 : return NS_OK;
1867 : }
1868 8 : ClonedMessageData data;
1869 4 : if (!BuildClonedMessageDataForChild(cc, aData, data)) {
1870 0 : return NS_ERROR_DOM_DATA_CLONE_ERR;
1871 : }
1872 8 : InfallibleTArray<mozilla::jsipc::CpowEntry> cpows;
1873 4 : if (aCpows && !cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
1874 0 : return NS_ERROR_UNEXPECTED;
1875 : }
1876 8 : if (!cc->SendAsyncMessage(PromiseFlatString(aMessage), cpows,
1877 8 : IPC::Principal(aPrincipal), data)) {
1878 0 : return NS_ERROR_UNEXPECTED;
1879 : }
1880 :
1881 4 : return NS_OK;
1882 : }
1883 : };
1884 :
1885 :
1886 3 : class nsAsyncMessageToSameProcessParent : public nsSameProcessAsyncMessageBase,
1887 : public SameProcessMessageQueue::Runnable
1888 : {
1889 : public:
1890 1 : nsAsyncMessageToSameProcessParent(JS::RootingContext* aRootingCx,
1891 : JS::Handle<JSObject*> aCpows)
1892 1 : : nsSameProcessAsyncMessageBase(aRootingCx, aCpows)
1893 1 : { }
1894 1 : nsresult HandleMessage() override
1895 : {
1896 1 : nsFrameMessageManager* ppm = nsFrameMessageManager::sSameProcessParentManager;
1897 1 : ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm), nullptr, ppm);
1898 1 : return NS_OK;
1899 : }
1900 : };
1901 :
1902 : /**
1903 : * Send messages to the imaginary parent process in a single-process scenario.
1904 : */
1905 : class SameChildProcessMessageManagerCallback : public MessageManagerCallback
1906 : {
1907 : public:
1908 1 : SameChildProcessMessageManagerCallback()
1909 1 : {
1910 1 : MOZ_COUNT_CTOR(SameChildProcessMessageManagerCallback);
1911 1 : }
1912 0 : ~SameChildProcessMessageManagerCallback() override
1913 0 : {
1914 0 : MOZ_COUNT_DTOR(SameChildProcessMessageManagerCallback);
1915 0 : }
1916 :
1917 0 : bool DoSendBlockingMessage(JSContext* aCx,
1918 : const nsAString& aMessage,
1919 : StructuredCloneData& aData,
1920 : JS::Handle<JSObject *> aCpows,
1921 : nsIPrincipal* aPrincipal,
1922 : nsTArray<StructuredCloneData>* aRetVal,
1923 : bool aIsSync) override
1924 : {
1925 0 : SameProcessMessageQueue* queue = SameProcessMessageQueue::Get();
1926 0 : queue->Flush();
1927 :
1928 0 : if (nsFrameMessageManager::sSameProcessParentManager) {
1929 0 : SameProcessCpowHolder cpows(JS::RootingContext::get(aCx), aCpows);
1930 0 : RefPtr<nsFrameMessageManager> ppm = nsFrameMessageManager::sSameProcessParentManager;
1931 0 : ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), nullptr, aMessage,
1932 0 : true, &aData, &cpows, aPrincipal, aRetVal);
1933 : }
1934 0 : return true;
1935 : }
1936 :
1937 1 : nsresult DoSendAsyncMessage(JSContext* aCx,
1938 : const nsAString& aMessage,
1939 : StructuredCloneData& aData,
1940 : JS::Handle<JSObject *> aCpows,
1941 : nsIPrincipal* aPrincipal) override
1942 : {
1943 1 : SameProcessMessageQueue* queue = SameProcessMessageQueue::Get();
1944 1 : JS::RootingContext* rcx = JS::RootingContext::get(aCx);
1945 : RefPtr<nsAsyncMessageToSameProcessParent> ev =
1946 3 : new nsAsyncMessageToSameProcessParent(rcx, aCpows);
1947 1 : nsresult rv = ev->Init(aMessage, aData, aPrincipal);
1948 :
1949 1 : if (NS_FAILED(rv)) {
1950 0 : return rv;
1951 : }
1952 1 : queue->Push(ev);
1953 1 : return NS_OK;
1954 : }
1955 :
1956 : };
1957 :
1958 :
1959 : // This creates the global parent process message manager.
1960 : nsresult
1961 1 : NS_NewParentProcessMessageManager(nsIMessageBroadcaster** aResult)
1962 : {
1963 1 : NS_ASSERTION(!nsFrameMessageManager::sParentProcessManager,
1964 : "Re-creating sParentProcessManager");
1965 : RefPtr<nsFrameMessageManager> mm = new nsFrameMessageManager(nullptr,
1966 : nullptr,
1967 2 : MM_CHROME | MM_PROCESSMANAGER | MM_BROADCASTER);
1968 1 : nsFrameMessageManager::sParentProcessManager = mm;
1969 1 : nsFrameMessageManager::NewProcessMessageManager(false); // Create same process message manager.
1970 1 : mm.forget(aResult);
1971 2 : return NS_OK;
1972 : }
1973 :
1974 :
1975 : nsFrameMessageManager*
1976 3 : nsFrameMessageManager::NewProcessMessageManager(bool aIsRemote)
1977 : {
1978 3 : if (!nsFrameMessageManager::sParentProcessManager) {
1979 : nsCOMPtr<nsIMessageBroadcaster> dummy =
1980 0 : do_GetService("@mozilla.org/parentprocessmessagemanager;1");
1981 : }
1982 :
1983 3 : MOZ_ASSERT(nsFrameMessageManager::sParentProcessManager,
1984 : "parent process manager not created");
1985 : nsFrameMessageManager* mm;
1986 3 : if (aIsRemote) {
1987 : // Callback is set in ContentParent::InitInternal so that the process has
1988 : // already started when we send pending scripts.
1989 2 : mm = new nsFrameMessageManager(nullptr,
1990 : nsFrameMessageManager::sParentProcessManager,
1991 2 : MM_CHROME | MM_PROCESSMANAGER);
1992 : } else {
1993 2 : mm = new nsFrameMessageManager(new SameParentProcessMessageManagerCallback(),
1994 : nsFrameMessageManager::sParentProcessManager,
1995 1 : MM_CHROME | MM_PROCESSMANAGER | MM_OWNSCALLBACK);
1996 1 : sSameProcessParentManager = mm;
1997 : }
1998 3 : return mm;
1999 : }
2000 :
2001 : nsresult
2002 3 : NS_NewChildProcessMessageManager(nsISyncMessageSender** aResult)
2003 : {
2004 3 : NS_ASSERTION(!nsFrameMessageManager::GetChildProcessManager(),
2005 : "Re-creating sChildProcessManager");
2006 :
2007 : MessageManagerCallback* cb;
2008 3 : if (XRE_IsParentProcess()) {
2009 1 : cb = new SameChildProcessMessageManagerCallback();
2010 : } else {
2011 2 : cb = new ChildProcessMessageManagerCallback();
2012 2 : RegisterStrongMemoryReporter(new MessageManagerReporter());
2013 : }
2014 : auto* mm = new nsFrameMessageManager(cb, nullptr,
2015 3 : MM_PROCESSMANAGER | MM_OWNSCALLBACK);
2016 3 : nsFrameMessageManager::SetChildProcessManager(mm);
2017 6 : RefPtr<ProcessGlobal> global = new ProcessGlobal(mm);
2018 3 : NS_ENSURE_TRUE(global->Init(), NS_ERROR_UNEXPECTED);
2019 3 : global.forget(aResult);
2020 3 : return NS_OK;
2021 : }
2022 :
2023 : bool
2024 0 : nsFrameMessageManager::MarkForCC()
2025 : {
2026 0 : for (auto iter = mListeners.Iter(); !iter.Done(); iter.Next()) {
2027 0 : nsAutoTObserverArray<nsMessageListenerInfo, 1>* listeners = iter.UserData();
2028 0 : uint32_t count = listeners->Length();
2029 0 : for (uint32_t i = 0; i < count; i++) {
2030 : nsCOMPtr<nsIMessageListener> strongListener =
2031 0 : listeners->ElementAt(i).mStrongListener;
2032 0 : if (strongListener) {
2033 0 : xpc_TryUnmarkWrappedGrayObject(strongListener);
2034 : }
2035 : }
2036 : }
2037 :
2038 0 : if (mRefCnt.IsPurple()) {
2039 0 : mRefCnt.RemovePurple();
2040 : }
2041 0 : return true;
2042 : }
2043 :
2044 5 : nsSameProcessAsyncMessageBase::nsSameProcessAsyncMessageBase(JS::RootingContext* aRootingCx,
2045 5 : JS::Handle<JSObject*> aCpows)
2046 : : mCpows(aRootingCx, aCpows)
2047 : #ifdef DEBUG
2048 5 : , mCalledInit(false)
2049 : #endif
2050 5 : { }
2051 :
2052 :
2053 : nsresult
2054 5 : nsSameProcessAsyncMessageBase::Init(const nsAString& aMessage,
2055 : StructuredCloneData& aData,
2056 : nsIPrincipal* aPrincipal)
2057 : {
2058 5 : if (!mData.Copy(aData)) {
2059 0 : Telemetry::Accumulate(Telemetry::IPC_SAME_PROCESS_MESSAGE_COPY_OOM_KB, aData.DataLength());
2060 0 : return NS_ERROR_OUT_OF_MEMORY;
2061 : }
2062 :
2063 5 : mMessage = aMessage;
2064 5 : mPrincipal = aPrincipal;
2065 : #ifdef DEBUG
2066 5 : mCalledInit = true;
2067 : #endif
2068 :
2069 5 : return NS_OK;
2070 : }
2071 :
2072 : void
2073 5 : nsSameProcessAsyncMessageBase::ReceiveMessage(nsISupports* aTarget,
2074 : nsIFrameLoader* aTargetFrameLoader,
2075 : nsFrameMessageManager* aManager)
2076 : {
2077 : // Make sure that we have called Init() and it has succeeded.
2078 5 : MOZ_ASSERT(mCalledInit);
2079 5 : if (aManager) {
2080 10 : SameProcessCpowHolder cpows(RootingCx(), mCpows);
2081 :
2082 10 : RefPtr<nsFrameMessageManager> mm = aManager;
2083 5 : mm->ReceiveMessage(aTarget, aTargetFrameLoader, mMessage, false, &mData,
2084 5 : &cpows, mPrincipal, nullptr);
2085 : }
2086 14 : }
|