Coverage Report

Created: 2018-09-25 14:53

/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
}