Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/workers/WorkerLoadInfo.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 "WorkerLoadInfo.h"
8
#include "WorkerPrivate.h"
9
10
#include "mozilla/dom/TabChild.h"
11
#include "mozilla/ipc/BackgroundUtils.h"
12
#include "mozilla/ipc/PBackgroundSharedTypes.h"
13
#include "mozilla/LoadContext.h"
14
#include "nsContentUtils.h"
15
#include "nsIContentSecurityPolicy.h"
16
#include "nsINetworkInterceptController.h"
17
#include "nsIProtocolHandler.h"
18
#include "nsITabChild.h"
19
#include "nsScriptSecurityManager.h"
20
#include "nsNetUtil.h"
21
22
namespace mozilla {
23
24
using namespace ipc;
25
26
namespace dom {
27
28
namespace {
29
30
class MainThreadReleaseRunnable final : public Runnable
31
{
32
  nsTArray<nsCOMPtr<nsISupports>> mDoomed;
33
  nsCOMPtr<nsILoadGroup> mLoadGroupToCancel;
34
35
public:
36
  MainThreadReleaseRunnable(nsTArray<nsCOMPtr<nsISupports>>& aDoomed,
37
                            nsCOMPtr<nsILoadGroup>& aLoadGroupToCancel)
38
    : mozilla::Runnable("MainThreadReleaseRunnable")
39
0
  {
40
0
    mDoomed.SwapElements(aDoomed);
41
0
    mLoadGroupToCancel.swap(aLoadGroupToCancel);
42
0
  }
43
44
  NS_INLINE_DECL_REFCOUNTING_INHERITED(MainThreadReleaseRunnable, Runnable)
45
46
  NS_IMETHOD
47
  Run() override
48
0
  {
49
0
    if (mLoadGroupToCancel) {
50
0
      mLoadGroupToCancel->Cancel(NS_BINDING_ABORTED);
51
0
      mLoadGroupToCancel = nullptr;
52
0
    }
53
0
54
0
    mDoomed.Clear();
55
0
    return NS_OK;
56
0
  }
57
58
private:
59
  ~MainThreadReleaseRunnable()
60
0
  { }
61
};
62
63
// Specialize this if there's some class that has multiple nsISupports bases.
64
template <class T>
65
struct ISupportsBaseInfo
66
{
67
  typedef T ISupportsBase;
68
};
69
70
template <template <class> class SmartPtr, class T>
71
inline void
72
SwapToISupportsArray(SmartPtr<T>& aSrc,
73
                     nsTArray<nsCOMPtr<nsISupports> >& aDest)
74
0
{
75
0
  nsCOMPtr<nsISupports>* dest = aDest.AppendElement();
76
0
77
0
  T* raw = nullptr;
78
0
  aSrc.swap(raw);
79
0
80
0
  nsISupports* rawSupports =
81
0
    static_cast<typename ISupportsBaseInfo<T>::ISupportsBase*>(raw);
82
0
  dest->swap(rawSupports);
83
0
}
Unexecuted instantiation: Unified_cpp_dom_workers1.cpp:void mozilla::dom::(anonymous namespace)::SwapToISupportsArray<nsCOMPtr, nsPIDOMWindowInner>(nsCOMPtr<nsPIDOMWindowInner>&, nsTArray<nsCOMPtr<nsISupports> >&)
Unexecuted instantiation: Unified_cpp_dom_workers1.cpp:void mozilla::dom::(anonymous namespace)::SwapToISupportsArray<nsCOMPtr, nsIScriptContext>(nsCOMPtr<nsIScriptContext>&, nsTArray<nsCOMPtr<nsISupports> >&)
Unexecuted instantiation: Unified_cpp_dom_workers1.cpp:void mozilla::dom::(anonymous namespace)::SwapToISupportsArray<nsCOMPtr, nsIURI>(nsCOMPtr<nsIURI>&, nsTArray<nsCOMPtr<nsISupports> >&)
Unexecuted instantiation: Unified_cpp_dom_workers1.cpp:void mozilla::dom::(anonymous namespace)::SwapToISupportsArray<nsCOMPtr, nsIPrincipal>(nsCOMPtr<nsIPrincipal>&, nsTArray<nsCOMPtr<nsISupports> >&)
Unexecuted instantiation: Unified_cpp_dom_workers1.cpp:void mozilla::dom::(anonymous namespace)::SwapToISupportsArray<nsCOMPtr, nsIChannel>(nsCOMPtr<nsIChannel>&, nsTArray<nsCOMPtr<nsISupports> >&)
Unexecuted instantiation: Unified_cpp_dom_workers1.cpp:void mozilla::dom::(anonymous namespace)::SwapToISupportsArray<nsCOMPtr, nsIContentSecurityPolicy>(nsCOMPtr<nsIContentSecurityPolicy>&, nsTArray<nsCOMPtr<nsISupports> >&)
Unexecuted instantiation: Unified_cpp_dom_workers1.cpp:void mozilla::dom::(anonymous namespace)::SwapToISupportsArray<nsCOMPtr, nsILoadGroup>(nsCOMPtr<nsILoadGroup>&, nsTArray<nsCOMPtr<nsISupports> >&)
Unexecuted instantiation: Unified_cpp_dom_workers1.cpp:void mozilla::dom::(anonymous namespace)::SwapToISupportsArray<RefPtr, mozilla::dom::WorkerLoadInfo::InterfaceRequestor>(RefPtr<mozilla::dom::WorkerLoadInfo::InterfaceRequestor>&, nsTArray<nsCOMPtr<nsISupports> >&)
84
85
} // anonymous
86
87
WorkerLoadInfo::WorkerLoadInfo()
88
  : mLoadFlags(nsIRequest::LOAD_NORMAL)
89
  , mWindowID(UINT64_MAX)
90
  , mReferrerPolicy(net::RP_Unset)
91
  , mFromWindow(false)
92
  , mEvalAllowed(false)
93
  , mReportCSPViolations(false)
94
  , mXHRParamsAllowed(false)
95
  , mPrincipalIsSystem(false)
96
  , mStorageAllowed(false)
97
  , mFirstPartyStorageAccessGranted(false)
98
  , mServiceWorkersTestingInWindow(false)
99
0
{
100
0
  MOZ_COUNT_CTOR(WorkerLoadInfo);
101
0
}
102
103
WorkerLoadInfo::~WorkerLoadInfo()
104
0
{
105
0
  MOZ_COUNT_DTOR(WorkerLoadInfo);
106
0
}
107
108
void
109
WorkerLoadInfo::StealFrom(WorkerLoadInfo& aOther)
110
0
{
111
0
  MOZ_ASSERT(!mBaseURI);
112
0
  aOther.mBaseURI.swap(mBaseURI);
113
0
114
0
  MOZ_ASSERT(!mResolvedScriptURI);
115
0
  aOther.mResolvedScriptURI.swap(mResolvedScriptURI);
116
0
117
0
  MOZ_ASSERT(!mPrincipal);
118
0
  aOther.mPrincipal.swap(mPrincipal);
119
0
120
0
  // mLoadingPrincipal can be null if this is a ServiceWorker.
121
0
  aOther.mLoadingPrincipal.swap(mLoadingPrincipal);
122
0
123
0
  MOZ_ASSERT(!mScriptContext);
124
0
  aOther.mScriptContext.swap(mScriptContext);
125
0
126
0
  MOZ_ASSERT(!mWindow);
127
0
  aOther.mWindow.swap(mWindow);
128
0
129
0
  MOZ_ASSERT(!mCSP);
130
0
  aOther.mCSP.swap(mCSP);
131
0
132
0
  MOZ_ASSERT(!mChannel);
133
0
  aOther.mChannel.swap(mChannel);
134
0
135
0
  MOZ_ASSERT(!mLoadGroup);
136
0
  aOther.mLoadGroup.swap(mLoadGroup);
137
0
138
0
  MOZ_ASSERT(!mInterfaceRequestor);
139
0
  aOther.mInterfaceRequestor.swap(mInterfaceRequestor);
140
0
141
0
  MOZ_ASSERT(!mPrincipalInfo);
142
0
  mPrincipalInfo = aOther.mPrincipalInfo.forget();
143
0
144
0
  mDomain = aOther.mDomain;
145
0
  mOrigin = aOther.mOrigin;
146
0
  mServiceWorkerCacheName = aOther.mServiceWorkerCacheName;
147
0
  mServiceWorkerDescriptor = aOther.mServiceWorkerDescriptor;
148
0
  mServiceWorkerRegistrationDescriptor = aOther.mServiceWorkerRegistrationDescriptor;
149
0
  mLoadFlags = aOther.mLoadFlags;
150
0
  mWindowID = aOther.mWindowID;
151
0
  mReferrerPolicy = aOther.mReferrerPolicy;
152
0
  mFromWindow = aOther.mFromWindow;
153
0
  mEvalAllowed = aOther.mEvalAllowed;
154
0
  mReportCSPViolations = aOther.mReportCSPViolations;
155
0
  mXHRParamsAllowed = aOther.mXHRParamsAllowed;
156
0
  mPrincipalIsSystem = aOther.mPrincipalIsSystem;
157
0
  mStorageAllowed = aOther.mStorageAllowed;
158
0
  mFirstPartyStorageAccessGranted = aOther.mFirstPartyStorageAccessGranted;
159
0
  mServiceWorkersTestingInWindow = aOther.mServiceWorkersTestingInWindow;
160
0
  mOriginAttributes = aOther.mOriginAttributes;
161
0
  mParentController = aOther.mParentController;
162
0
}
163
164
nsresult
165
WorkerLoadInfo::SetPrincipalOnMainThread(nsIPrincipal* aPrincipal,
166
                                         nsILoadGroup* aLoadGroup)
167
0
{
168
0
  AssertIsOnMainThread();
169
0
  MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(aLoadGroup, aPrincipal));
170
0
171
0
  mPrincipal = aPrincipal;
172
0
  mPrincipalIsSystem = nsContentUtils::IsSystemPrincipal(aPrincipal);
173
0
174
0
  nsresult rv = aPrincipal->GetCsp(getter_AddRefs(mCSP));
175
0
  NS_ENSURE_SUCCESS(rv, rv);
176
0
177
0
  if (mCSP) {
178
0
    mCSP->GetAllowsEval(&mReportCSPViolations, &mEvalAllowed);
179
0
  } else {
180
0
    mEvalAllowed = true;
181
0
    mReportCSPViolations = false;
182
0
  }
183
0
184
0
  mLoadGroup = aLoadGroup;
185
0
186
0
  mPrincipalInfo = new PrincipalInfo();
187
0
  mOriginAttributes = nsContentUtils::GetOriginAttributes(aLoadGroup);
188
0
189
0
  rv = PrincipalToPrincipalInfo(aPrincipal, mPrincipalInfo);
190
0
  NS_ENSURE_SUCCESS(rv, rv);
191
0
192
0
  rv = nsContentUtils::GetUTFOrigin(aPrincipal, mOrigin);
193
0
  NS_ENSURE_SUCCESS(rv, rv);
194
0
195
0
  return NS_OK;
196
0
}
197
198
nsresult
199
WorkerLoadInfo::GetPrincipalAndLoadGroupFromChannel(nsIChannel* aChannel,
200
                                                    nsIPrincipal** aPrincipalOut,
201
                                                    nsILoadGroup** aLoadGroupOut)
202
0
{
203
0
  AssertIsOnMainThread();
204
0
  MOZ_DIAGNOSTIC_ASSERT(aChannel);
205
0
  MOZ_DIAGNOSTIC_ASSERT(aPrincipalOut);
206
0
  MOZ_DIAGNOSTIC_ASSERT(aLoadGroupOut);
207
0
208
0
  // Initial triggering principal should be set
209
0
  NS_ENSURE_TRUE(mLoadingPrincipal, NS_ERROR_DOM_INVALID_STATE_ERR);
210
0
211
0
  nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
212
0
  MOZ_DIAGNOSTIC_ASSERT(ssm);
213
0
214
0
  nsCOMPtr<nsIPrincipal> channelPrincipal;
215
0
  nsresult rv = ssm->GetChannelResultPrincipal(aChannel, getter_AddRefs(channelPrincipal));
216
0
  NS_ENSURE_SUCCESS(rv, rv);
217
0
218
0
  // Every time we call GetChannelResultPrincipal() it will return a different
219
0
  // null principal for a data URL.  We don't want to change the worker's
220
0
  // principal again, though.  Instead just keep the original null principal we
221
0
  // first got from the channel.
222
0
  //
223
0
  // Note, we don't do this by setting principalToInherit on the channel's
224
0
  // load info because we don't yet have the first null principal when we
225
0
  // create the channel.
226
0
  if (mPrincipal && mPrincipal->GetIsNullPrincipal() &&
227
0
                    channelPrincipal->GetIsNullPrincipal()) {
228
0
    channelPrincipal = mPrincipal;
229
0
  }
230
0
231
0
  nsCOMPtr<nsILoadGroup> channelLoadGroup;
232
0
  rv = aChannel->GetLoadGroup(getter_AddRefs(channelLoadGroup));
233
0
  NS_ENSURE_SUCCESS(rv, rv);
234
0
  MOZ_ASSERT(channelLoadGroup);
235
0
236
0
  // If the loading principal is the system principal then the channel
237
0
  // principal must also be the system principal (we do not allow chrome
238
0
  // code to create workers with non-chrome scripts, and if we ever decide
239
0
  // to change this we need to make sure we don't always set
240
0
  // mPrincipalIsSystem to true in WorkerPrivate::GetLoadInfo()). Otherwise
241
0
  // this channel principal must be same origin with the load principal (we
242
0
  // check again here in case redirects changed the location of the script).
243
0
  if (nsContentUtils::IsSystemPrincipal(mLoadingPrincipal)) {
244
0
    if (!nsContentUtils::IsSystemPrincipal(channelPrincipal)) {
245
0
      nsCOMPtr<nsIURI> finalURI;
246
0
      rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(finalURI));
247
0
      NS_ENSURE_SUCCESS(rv, rv);
248
0
249
0
      // See if this is a resource URI. Since JSMs usually come from
250
0
      // resource:// URIs we're currently considering all URIs with the
251
0
      // URI_IS_UI_RESOURCE flag as valid for creating privileged workers.
252
0
      bool isResource;
253
0
      rv = NS_URIChainHasFlags(finalURI,
254
0
                               nsIProtocolHandler::URI_IS_UI_RESOURCE,
255
0
                               &isResource);
256
0
      NS_ENSURE_SUCCESS(rv, rv);
257
0
258
0
      if (isResource) {
259
0
        // Assign the system principal to the resource:// worker only if it
260
0
        // was loaded from code using the system principal.
261
0
        channelPrincipal = mLoadingPrincipal;
262
0
      } else {
263
0
        return NS_ERROR_DOM_BAD_URI;
264
0
      }
265
0
    }
266
0
  }
267
0
268
0
  // The principal can change, but it should still match the original
269
0
  // load group's appId and browser element flag.
270
0
  MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(channelLoadGroup, channelPrincipal));
271
0
272
0
  channelPrincipal.forget(aPrincipalOut);
273
0
  channelLoadGroup.forget(aLoadGroupOut);
274
0
275
0
  return NS_OK;
276
0
}
277
278
nsresult
279
WorkerLoadInfo::SetPrincipalFromChannel(nsIChannel* aChannel)
280
0
{
281
0
  AssertIsOnMainThread();
282
0
283
0
  nsCOMPtr<nsIPrincipal> principal;
284
0
  nsCOMPtr<nsILoadGroup> loadGroup;
285
0
  nsresult rv = GetPrincipalAndLoadGroupFromChannel(aChannel,
286
0
                                                    getter_AddRefs(principal),
287
0
                                                    getter_AddRefs(loadGroup));
288
0
  NS_ENSURE_SUCCESS(rv, rv);
289
0
290
0
  return SetPrincipalOnMainThread(principal, loadGroup);
291
0
}
292
293
bool
294
WorkerLoadInfo::FinalChannelPrincipalIsValid(nsIChannel* aChannel)
295
0
{
296
0
  AssertIsOnMainThread();
297
0
298
0
  nsCOMPtr<nsIPrincipal> principal;
299
0
  nsCOMPtr<nsILoadGroup> loadGroup;
300
0
  nsresult rv = GetPrincipalAndLoadGroupFromChannel(aChannel,
301
0
                                                    getter_AddRefs(principal),
302
0
                                                    getter_AddRefs(loadGroup));
303
0
  NS_ENSURE_SUCCESS(rv, false);
304
0
305
0
306
0
  // Verify that the channel is still a null principal.  We don't care
307
0
  // if these are the exact same null principal object, though.  From
308
0
  // the worker's perspective its the same effect.
309
0
  if (principal->GetIsNullPrincipal() && mPrincipal->GetIsNullPrincipal()) {
310
0
    return true;
311
0
  }
312
0
313
0
  // Otherwise we require exact equality.  Redirects can happen, but they
314
0
  // are not allowed to change our principal.
315
0
  if (principal->Equals(mPrincipal)) {
316
0
    return true;
317
0
  }
318
0
319
0
  return false;
320
0
}
321
322
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
323
bool
324
WorkerLoadInfo::PrincipalIsValid() const
325
0
{
326
0
  return mPrincipal && mPrincipalInfo &&
327
0
         mPrincipalInfo->type() != PrincipalInfo::T__None &&
328
0
         mPrincipalInfo->type() <= PrincipalInfo::T__Last;
329
0
}
330
331
bool
332
WorkerLoadInfo::PrincipalURIMatchesScriptURL()
333
0
{
334
0
  AssertIsOnMainThread();
335
0
336
0
  nsAutoCString scheme;
337
0
  nsresult rv = mBaseURI->GetScheme(scheme);
338
0
  NS_ENSURE_SUCCESS(rv, false);
339
0
340
0
  // A system principal must either be a blob URL or a resource JSM.
341
0
  if (mPrincipal->GetIsSystemPrincipal()) {
342
0
    if (scheme == NS_LITERAL_CSTRING("blob")) {
343
0
      return true;
344
0
    }
345
0
346
0
    bool isResource = false;
347
0
    nsresult rv = NS_URIChainHasFlags(mBaseURI,
348
0
                                      nsIProtocolHandler::URI_IS_UI_RESOURCE,
349
0
                                      &isResource);
350
0
    NS_ENSURE_SUCCESS(rv, false);
351
0
352
0
    return isResource;
353
0
  }
354
0
355
0
  // A null principal can occur for a data URL worker script or a blob URL
356
0
  // worker script from a sandboxed iframe.
357
0
  if (mPrincipal->GetIsNullPrincipal()) {
358
0
    return scheme == NS_LITERAL_CSTRING("data") ||
359
0
           scheme == NS_LITERAL_CSTRING("blob");
360
0
  }
361
0
362
0
  // The principal for a blob: URL worker script does not have a matching URL.
363
0
  // This is likely a bug in our referer setting logic, but exempt it for now.
364
0
  // This is another reason we should fix bug 1340694 so that referer does not
365
0
  // depend on the principal URI.
366
0
  if (scheme == NS_LITERAL_CSTRING("blob")) {
367
0
    return true;
368
0
  }
369
0
370
0
  nsCOMPtr<nsIURI> principalURI;
371
0
  rv = mPrincipal->GetURI(getter_AddRefs(principalURI));
372
0
  NS_ENSURE_SUCCESS(rv, false);
373
0
  NS_ENSURE_TRUE(principalURI, false);
374
0
375
0
  if (nsScriptSecurityManager::SecurityCompareURIs(mBaseURI, principalURI)) {
376
0
    return true;
377
0
  }
378
0
379
0
  // If strict file origin policy is in effect, local files will always fail
380
0
  // SecurityCompareURIs unless they are identical. Explicitly check file origin
381
0
  // policy, in that case.
382
0
  if (nsScriptSecurityManager::GetStrictFileOriginPolicy() &&
383
0
      NS_URIIsLocalFile(mBaseURI) &&
384
0
      NS_RelaxStrictFileOriginPolicy(mBaseURI, principalURI)) {
385
0
    return true;
386
0
  }
387
0
388
0
  return false;
389
0
}
390
#endif // MOZ_DIAGNOSTIC_ASSERT_ENABLED
391
392
bool
393
WorkerLoadInfo::ProxyReleaseMainThreadObjects(WorkerPrivate* aWorkerPrivate)
394
0
{
395
0
  nsCOMPtr<nsILoadGroup> nullLoadGroup;
396
0
  return ProxyReleaseMainThreadObjects(aWorkerPrivate, nullLoadGroup);
397
0
}
398
399
bool
400
WorkerLoadInfo::ProxyReleaseMainThreadObjects(WorkerPrivate* aWorkerPrivate,
401
                                              nsCOMPtr<nsILoadGroup>& aLoadGroupToCancel)
402
0
{
403
0
404
0
  static const uint32_t kDoomedCount = 10;
405
0
  nsTArray<nsCOMPtr<nsISupports>> doomed(kDoomedCount);
406
0
407
0
  SwapToISupportsArray(mWindow, doomed);
408
0
  SwapToISupportsArray(mScriptContext, doomed);
409
0
  SwapToISupportsArray(mBaseURI, doomed);
410
0
  SwapToISupportsArray(mResolvedScriptURI, doomed);
411
0
  SwapToISupportsArray(mPrincipal, doomed);
412
0
  SwapToISupportsArray(mLoadingPrincipal, doomed);
413
0
  SwapToISupportsArray(mChannel, doomed);
414
0
  SwapToISupportsArray(mCSP, doomed);
415
0
  SwapToISupportsArray(mLoadGroup, doomed);
416
0
  SwapToISupportsArray(mInterfaceRequestor, doomed);
417
0
  // Before adding anything here update kDoomedCount above!
418
0
419
0
  MOZ_ASSERT(doomed.Length() == kDoomedCount);
420
0
421
0
  RefPtr<MainThreadReleaseRunnable> runnable =
422
0
    new MainThreadReleaseRunnable(doomed, aLoadGroupToCancel);
423
0
  return NS_SUCCEEDED(aWorkerPrivate->DispatchToMainThread(runnable.forget()));
424
0
}
425
426
WorkerLoadInfo::
427
InterfaceRequestor::InterfaceRequestor(nsIPrincipal* aPrincipal,
428
                                       nsILoadGroup* aLoadGroup)
429
0
{
430
0
  MOZ_ASSERT(NS_IsMainThread());
431
0
  MOZ_ASSERT(aPrincipal);
432
0
433
0
  // Look for an existing LoadContext.  This is optional and it's ok if
434
0
  // we don't find one.
435
0
  nsCOMPtr<nsILoadContext> baseContext;
436
0
  if (aLoadGroup) {
437
0
    nsCOMPtr<nsIInterfaceRequestor> callbacks;
438
0
    aLoadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
439
0
    if (callbacks) {
440
0
      callbacks->GetInterface(NS_GET_IID(nsILoadContext),
441
0
                              getter_AddRefs(baseContext));
442
0
    }
443
0
    mOuterRequestor = callbacks;
444
0
  }
445
0
446
0
  mLoadContext = new LoadContext(aPrincipal, baseContext);
447
0
}
448
449
void
450
WorkerLoadInfo::
451
InterfaceRequestor::MaybeAddTabChild(nsILoadGroup* aLoadGroup)
452
0
{
453
0
  MOZ_ASSERT(NS_IsMainThread());
454
0
455
0
  if (!aLoadGroup) {
456
0
    return;
457
0
  }
458
0
459
0
  nsCOMPtr<nsIInterfaceRequestor> callbacks;
460
0
  aLoadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
461
0
  if (!callbacks) {
462
0
    return;
463
0
  }
464
0
465
0
  nsCOMPtr<nsITabChild> tabChild;
466
0
  callbacks->GetInterface(NS_GET_IID(nsITabChild), getter_AddRefs(tabChild));
467
0
  if (!tabChild) {
468
0
    return;
469
0
  }
470
0
471
0
  // Use weak references to the tab child.  Holding a strong reference will
472
0
  // not prevent an ActorDestroy() from being called on the TabChild.
473
0
  // Therefore, we should let the TabChild destroy itself as soon as possible.
474
0
  mTabChildList.AppendElement(do_GetWeakReference(tabChild));
475
0
}
476
477
NS_IMETHODIMP
478
WorkerLoadInfo::
479
InterfaceRequestor::GetInterface(const nsIID& aIID, void** aSink)
480
0
{
481
0
  MOZ_ASSERT(NS_IsMainThread());
482
0
  MOZ_ASSERT(mLoadContext);
483
0
484
0
  if (aIID.Equals(NS_GET_IID(nsILoadContext))) {
485
0
    nsCOMPtr<nsILoadContext> ref = mLoadContext;
486
0
    ref.forget(aSink);
487
0
    return NS_OK;
488
0
  }
489
0
490
0
  // If we still have an active nsITabChild, then return it.  Its possible,
491
0
  // though, that all of the TabChild objects have been destroyed.  In that
492
0
  // case we return NS_NOINTERFACE.
493
0
  if (aIID.Equals(NS_GET_IID(nsITabChild))) {
494
0
    nsCOMPtr<nsITabChild> tabChild = GetAnyLiveTabChild();
495
0
    if (!tabChild) {
496
0
      return NS_NOINTERFACE;
497
0
    }
498
0
    tabChild.forget(aSink);
499
0
    return NS_OK;
500
0
  }
501
0
502
0
  if (aIID.Equals(NS_GET_IID(nsINetworkInterceptController)) &&
503
0
      mOuterRequestor) {
504
0
    // If asked for the network intercept controller, ask the outer requestor,
505
0
    // which could be the docshell.
506
0
    return mOuterRequestor->GetInterface(aIID, aSink);
507
0
  }
508
0
509
0
  return NS_NOINTERFACE;
510
0
}
511
512
already_AddRefed<nsITabChild>
513
WorkerLoadInfo::
514
InterfaceRequestor::GetAnyLiveTabChild()
515
0
{
516
0
  MOZ_ASSERT(NS_IsMainThread());
517
0
518
0
  // Search our list of known TabChild objects for one that still exists.
519
0
  while (!mTabChildList.IsEmpty()) {
520
0
    nsCOMPtr<nsITabChild> tabChild =
521
0
      do_QueryReferent(mTabChildList.LastElement());
522
0
523
0
    // Does this tab child still exist?  If so, return it.  We are done.  If the
524
0
    // PBrowser actor is no longer useful, don't bother returning this tab.
525
0
    if (tabChild && !static_cast<TabChild*>(tabChild.get())->IsDestroyed()) {
526
0
      return tabChild.forget();
527
0
    }
528
0
529
0
    // Otherwise remove the stale weak reference and check the next one
530
0
    mTabChildList.RemoveLastElement();
531
0
  }
532
0
533
0
  return nullptr;
534
0
}
535
536
NS_IMPL_ADDREF(WorkerLoadInfo::InterfaceRequestor)
537
NS_IMPL_RELEASE(WorkerLoadInfo::InterfaceRequestor)
538
NS_IMPL_QUERY_INTERFACE(WorkerLoadInfo::InterfaceRequestor,
539
                        nsIInterfaceRequestor)
540
541
} // dom namespace
542
} // mozilla namespace