Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/serviceworkers/ServiceWorkerContainer.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 "ServiceWorkerContainer.h"
8
9
#include "nsContentPolicyUtils.h"
10
#include "nsContentSecurityManager.h"
11
#include "nsContentUtils.h"
12
#include "nsIDocument.h"
13
#include "nsIServiceWorkerManager.h"
14
#include "nsIScriptError.h"
15
#include "nsIURL.h"
16
#include "nsNetUtil.h"
17
#include "nsPIDOMWindow.h"
18
#include "mozilla/Services.h"
19
#include "mozilla/StaticPrefs.h"
20
21
#include "nsCycleCollectionParticipant.h"
22
#include "nsServiceManagerUtils.h"
23
24
#include "mozilla/LoadInfo.h"
25
#include "mozilla/dom/DOMMozPromiseRequestHolder.h"
26
#include "mozilla/dom/Navigator.h"
27
#include "mozilla/dom/Promise.h"
28
#include "mozilla/dom/ServiceWorker.h"
29
#include "mozilla/dom/ServiceWorkerContainerBinding.h"
30
31
#include "RemoteServiceWorkerContainerImpl.h"
32
#include "ServiceWorker.h"
33
#include "ServiceWorkerContainerImpl.h"
34
#include "ServiceWorkerRegistration.h"
35
#include "ServiceWorkerUtils.h"
36
37
namespace mozilla {
38
namespace dom {
39
40
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ServiceWorkerContainer)
41
0
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
42
43
NS_IMPL_ADDREF_INHERITED(ServiceWorkerContainer, DOMEventTargetHelper)
44
NS_IMPL_RELEASE_INHERITED(ServiceWorkerContainer, DOMEventTargetHelper)
45
46
NS_IMPL_CYCLE_COLLECTION_INHERITED(ServiceWorkerContainer, DOMEventTargetHelper,
47
                                   mControllerWorker, mReadyPromise)
48
49
namespace {
50
51
bool
52
IsInPrivateBrowsing(JSContext* const aCx)
53
0
{
54
0
  if (const nsCOMPtr<nsIGlobalObject> global = xpc::CurrentNativeGlobal(aCx)) {
55
0
    if (const nsCOMPtr<nsIPrincipal> principal = global->PrincipalOrNull()) {
56
0
      return principal->GetPrivateBrowsingId() > 0;
57
0
    }
58
0
  }
59
0
  return false;
60
0
}
61
62
bool
63
IsServiceWorkersTestingEnabledInWindow(JSObject* const aGlobal)
64
0
{
65
0
  if (const nsCOMPtr<nsPIDOMWindowInner> innerWindow = Navigator::GetWindowFromGlobal(aGlobal)) {
66
0
    if (const nsCOMPtr<nsPIDOMWindowOuter> outerWindow = innerWindow->GetOuterWindow()) {
67
0
      return outerWindow->GetServiceWorkersTestingEnabled();
68
0
    }
69
0
  }
70
0
  return false;
71
0
}
72
73
}
74
75
/* static */ bool
76
ServiceWorkerContainer::IsEnabled(JSContext* aCx, JSObject* aGlobal)
77
0
{
78
0
  MOZ_ASSERT(NS_IsMainThread());
79
0
80
0
  JS::Rooted<JSObject*> global(aCx, aGlobal);
81
0
82
0
  if (!StaticPrefs::dom_serviceWorkers_enabled()) {
83
0
    return false;
84
0
  }
85
0
86
0
  if (IsInPrivateBrowsing(aCx)) {
87
0
    return false;
88
0
  }
89
0
90
0
  if (IsSecureContextOrObjectIsFromSecureContext(aCx, global)) {
91
0
    return true;
92
0
  }
93
0
94
0
  const bool isTestingEnabledInWindow = IsServiceWorkersTestingEnabledInWindow(global);
95
0
  const bool isTestingEnabledByPref = StaticPrefs::dom_serviceWorkers_testing_enabled();
96
0
  const bool isTestingEnabled = isTestingEnabledByPref || isTestingEnabledInWindow;
97
0
98
0
  return isTestingEnabled;
99
0
}
100
101
// static
102
already_AddRefed<ServiceWorkerContainer>
103
ServiceWorkerContainer::Create(nsIGlobalObject* aGlobal)
104
0
{
105
0
  RefPtr<Inner> inner;
106
0
  if (ServiceWorkerParentInterceptEnabled()) {
107
0
    inner = new RemoteServiceWorkerContainerImpl();
108
0
  } else {
109
0
    inner = new ServiceWorkerContainerImpl();
110
0
  }
111
0
  NS_ENSURE_TRUE(inner, nullptr);
112
0
113
0
  RefPtr<ServiceWorkerContainer> ref =
114
0
    new ServiceWorkerContainer(aGlobal, inner.forget());
115
0
  return ref.forget();
116
0
}
117
118
ServiceWorkerContainer::ServiceWorkerContainer(nsIGlobalObject* aGlobal,
119
                                               already_AddRefed<ServiceWorkerContainer::Inner> aInner)
120
  : DOMEventTargetHelper(aGlobal)
121
  , mInner(aInner)
122
0
{
123
0
  mInner->AddContainer(this);
124
0
  Maybe<ServiceWorkerDescriptor> controller = aGlobal->GetController();
125
0
  if (controller.isSome()) {
126
0
    mControllerWorker = aGlobal->GetOrCreateServiceWorker(controller.ref());
127
0
  }
128
0
}
129
130
ServiceWorkerContainer::~ServiceWorkerContainer()
131
0
{
132
0
  mInner->RemoveContainer(this);
133
0
}
134
135
void
136
ServiceWorkerContainer::DisconnectFromOwner()
137
0
{
138
0
  mControllerWorker = nullptr;
139
0
  mReadyPromise = nullptr;
140
0
  DOMEventTargetHelper::DisconnectFromOwner();
141
0
}
142
143
void
144
ServiceWorkerContainer::ControllerChanged(ErrorResult& aRv)
145
0
{
146
0
  nsCOMPtr<nsIGlobalObject> go = GetParentObject();
147
0
  if (!go) {
148
0
    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
149
0
    return;
150
0
  }
151
0
  mControllerWorker = go->GetOrCreateServiceWorker(go->GetController().ref());
152
0
  aRv = DispatchTrustedEvent(NS_LITERAL_STRING("controllerchange"));
153
0
}
154
155
JSObject*
156
ServiceWorkerContainer::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
157
0
{
158
0
  return ServiceWorkerContainer_Binding::Wrap(aCx, this, aGivenProto);
159
0
}
160
161
namespace {
162
163
already_AddRefed<nsIURI>
164
GetBaseURIFromGlobal(nsIGlobalObject* aGlobal, ErrorResult& aRv)
165
0
{
166
0
  // It would be nice not to require a window here, but right
167
0
  // now we don't have a great way to get the base URL just
168
0
  // from the nsIGlobalObject.
169
0
  nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal);
170
0
  if (!window) {
171
0
    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
172
0
    return nullptr;
173
0
  }
174
0
175
0
  nsIDocument* doc = window->GetExtantDoc();
176
0
  if (!doc) {
177
0
    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
178
0
    return nullptr;
179
0
  }
180
0
181
0
  nsCOMPtr<nsIURI> baseURI = doc->GetDocBaseURI();
182
0
  if (!baseURI) {
183
0
    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
184
0
    return nullptr;
185
0
  }
186
0
187
0
  return baseURI.forget();
188
0
}
189
190
} // anonymous namespace
191
192
already_AddRefed<Promise>
193
ServiceWorkerContainer::Register(const nsAString& aScriptURL,
194
                                 const RegistrationOptions& aOptions,
195
                                 ErrorResult& aRv)
196
0
{
197
0
  // Note, we can't use GetGlobalIfValid() from the start here.  If we
198
0
  // hit a storage failure we want to log a message with the final
199
0
  // scope string we put together below.
200
0
  nsIGlobalObject* global = GetParentObject();
201
0
  if (!global) {
202
0
    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
203
0
    return nullptr;
204
0
  }
205
0
206
0
  Maybe<ClientInfo> clientInfo = global->GetClientInfo();
207
0
  if (clientInfo.isNothing()) {
208
0
    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
209
0
    return nullptr;
210
0
  }
211
0
212
0
  nsCOMPtr<nsIURI> baseURI = GetBaseURIFromGlobal(global, aRv);
213
0
  if (aRv.Failed()) {
214
0
    return nullptr;
215
0
  }
216
0
217
0
  nsresult rv;
218
0
  nsCOMPtr<nsIURI> scriptURI;
219
0
  rv = NS_NewURI(getter_AddRefs(scriptURI), aScriptURL, nullptr, baseURI);
220
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
221
0
    aRv.ThrowTypeError<MSG_INVALID_URL>(aScriptURL);
222
0
    return nullptr;
223
0
  }
224
0
225
0
  // In ServiceWorkerContainer.register() the scope argument is parsed against
226
0
  // different base URLs depending on whether it was passed or not.
227
0
  nsCOMPtr<nsIURI> scopeURI;
228
0
229
0
  // Step 4. If none passed, parse against script's URL
230
0
  if (!aOptions.mScope.WasPassed()) {
231
0
    NS_NAMED_LITERAL_STRING(defaultScope, "./");
232
0
    rv = NS_NewURI(getter_AddRefs(scopeURI), defaultScope,
233
0
                   nullptr, scriptURI);
234
0
    if (NS_WARN_IF(NS_FAILED(rv))) {
235
0
      nsAutoCString spec;
236
0
      scriptURI->GetSpec(spec);
237
0
      NS_ConvertUTF8toUTF16 wSpec(spec);
238
0
      aRv.ThrowTypeError<MSG_INVALID_SCOPE>(defaultScope, wSpec);
239
0
      return nullptr;
240
0
    }
241
0
  } else {
242
0
    // Step 5. Parse against entry settings object's base URL.
243
0
    rv = NS_NewURI(getter_AddRefs(scopeURI), aOptions.mScope.Value(),
244
0
                   nullptr, baseURI);
245
0
    if (NS_WARN_IF(NS_FAILED(rv))) {
246
0
      nsIURI* uri = baseURI ? baseURI : scriptURI;
247
0
      nsAutoCString spec;
248
0
      uri->GetSpec(spec);
249
0
      NS_ConvertUTF8toUTF16 wSpec(spec);
250
0
      aRv.ThrowTypeError<MSG_INVALID_SCOPE>(aOptions.mScope.Value(), wSpec);
251
0
      return nullptr;
252
0
    }
253
0
  }
254
0
255
0
  // Strip the any ref from both the script and scope URLs.
256
0
  nsCOMPtr<nsIURI> cloneWithoutRef;
257
0
  aRv = NS_GetURIWithoutRef(scriptURI, getter_AddRefs(cloneWithoutRef));
258
0
  if (aRv.Failed()) {
259
0
    return nullptr;
260
0
  }
261
0
  scriptURI = cloneWithoutRef.forget();
262
0
263
0
  aRv = NS_GetURIWithoutRef(scopeURI, getter_AddRefs(cloneWithoutRef));
264
0
  if (aRv.Failed()) {
265
0
    return nullptr;
266
0
  }
267
0
  scopeURI = cloneWithoutRef.forget();
268
0
269
0
  aRv = ServiceWorkerScopeAndScriptAreValid(clientInfo.ref(),
270
0
                                            scopeURI,
271
0
                                            scriptURI);
272
0
  if (aRv.Failed()) {
273
0
    return nullptr;
274
0
  }
275
0
276
0
  nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(global);
277
0
  if (!window) {
278
0
    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
279
0
    return nullptr;
280
0
  }
281
0
282
0
  nsIDocument* doc = window->GetExtantDoc();
283
0
  if (!doc) {
284
0
    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
285
0
    return nullptr;
286
0
  }
287
0
288
0
  // The next section of code executes an NS_CheckContentLoadPolicy()
289
0
  // check.  This is necessary to enforce the CSP of the calling client.
290
0
  // Currently this requires an nsIDocument.  Once bug 965637 lands we
291
0
  // should try to move this into ServiceWorkerScopeAndScriptAreValid()
292
0
  // using the ClientInfo instead of doing a window-specific check here.
293
0
  // See bug 1455077 for further investigation.
294
0
  nsCOMPtr<nsILoadInfo> secCheckLoadInfo =
295
0
    new mozilla::net::LoadInfo(doc->NodePrincipal(), // loading principal
296
0
                               doc->NodePrincipal(), // triggering principal
297
0
                               doc,                  // loading node
298
0
                               nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK,
299
0
                               nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER);
300
0
301
0
  // Check content policy.
302
0
  int16_t decision = nsIContentPolicy::ACCEPT;
303
0
  rv = NS_CheckContentLoadPolicy(scriptURI,
304
0
                                 secCheckLoadInfo,
305
0
                                 NS_LITERAL_CSTRING("application/javascript"),
306
0
                                 &decision);
307
0
  if (NS_FAILED(rv)) {
308
0
    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
309
0
    return nullptr;
310
0
311
0
  }
312
0
  if (NS_WARN_IF(decision != nsIContentPolicy::ACCEPT)) {
313
0
    aRv.Throw(NS_ERROR_CONTENT_BLOCKED);
314
0
    return nullptr;
315
0
  }
316
0
317
0
  // Get the string representation for both the script and scope since
318
0
  // we sanitized them above.
319
0
  nsCString cleanedScopeURL;
320
0
  aRv = scopeURI->GetSpec(cleanedScopeURL);
321
0
  if (aRv.Failed()) {
322
0
    return nullptr;
323
0
  }
324
0
325
0
  nsCString cleanedScriptURL;
326
0
  aRv = scriptURI->GetSpec(cleanedScriptURL);
327
0
  if (aRv.Failed()) {
328
0
    return nullptr;
329
0
  }
330
0
331
0
  // Verify that the global is valid and has permission to store
332
0
  // data.  We perform this late so that we can report the final
333
0
  // scope URL in any error message.
334
0
  Unused << GetGlobalIfValid(aRv, [&](nsIDocument* aDoc) {
335
0
    NS_ConvertUTF8toUTF16 reportScope(cleanedScopeURL);
336
0
    const char16_t* param[] = { reportScope.get() };
337
0
    nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
338
0
                                    NS_LITERAL_CSTRING("Service Workers"),
339
0
                                    aDoc, nsContentUtils::eDOM_PROPERTIES,
340
0
                                    "ServiceWorkerRegisterStorageError",
341
0
                                    param, 1);
342
0
  });
343
0
344
0
  window->NoteCalledRegisterForServiceWorkerScope(cleanedScopeURL);
345
0
346
0
  RefPtr<Promise> outer = Promise::Create(global, aRv);
347
0
  if (aRv.Failed()) {
348
0
    return nullptr;
349
0
  }
350
0
351
0
  RefPtr<ServiceWorkerContainer> self = this;
352
0
353
0
  mInner->Register(
354
0
    clientInfo.ref(), cleanedScopeURL, cleanedScriptURL, aOptions.mUpdateViaCache,
355
0
    [self, outer] (const ServiceWorkerRegistrationDescriptor& aDesc) {
356
0
      ErrorResult rv;
357
0
      nsIGlobalObject* global = self->GetGlobalIfValid(rv);
358
0
      if (rv.Failed()) {
359
0
        outer->MaybeReject(rv);
360
0
        return;
361
0
      }
362
0
      RefPtr<ServiceWorkerRegistration> reg =
363
0
        global->GetOrCreateServiceWorkerRegistration(aDesc);
364
0
      outer->MaybeResolve(reg);
365
0
    }, [outer] (ErrorResult& aRv) {
366
0
      outer->MaybeReject(aRv);
367
0
    });
368
0
369
0
  return outer.forget();
370
0
}
371
372
already_AddRefed<ServiceWorker>
373
ServiceWorkerContainer::GetController()
374
0
{
375
0
  RefPtr<ServiceWorker> ref = mControllerWorker;
376
0
  return ref.forget();
377
0
}
378
379
already_AddRefed<Promise>
380
ServiceWorkerContainer::GetRegistrations(ErrorResult& aRv)
381
0
{
382
0
  nsIGlobalObject* global = GetGlobalIfValid(aRv, [](nsIDocument* aDoc) {
383
0
    nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
384
0
                                    NS_LITERAL_CSTRING("Service Workers"), aDoc,
385
0
                                    nsContentUtils::eDOM_PROPERTIES,
386
0
                                    "ServiceWorkerGetRegistrationStorageError");
387
0
  });
388
0
  if (aRv.Failed()) {
389
0
    return nullptr;
390
0
  }
391
0
392
0
  Maybe<ClientInfo> clientInfo = global->GetClientInfo();
393
0
  if (clientInfo.isNothing()) {
394
0
    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
395
0
    return nullptr;
396
0
  }
397
0
398
0
  RefPtr<Promise> outer = Promise::Create(global, aRv);
399
0
  if (aRv.Failed()) {
400
0
    return nullptr;
401
0
  }
402
0
403
0
  RefPtr<ServiceWorkerContainer> self = this;
404
0
405
0
  mInner->GetRegistrations(clientInfo.ref(),
406
0
    [self, outer] (const nsTArray<ServiceWorkerRegistrationDescriptor>& aDescList) {
407
0
      ErrorResult rv;
408
0
      nsIGlobalObject* global = self->GetGlobalIfValid(rv);
409
0
      if (rv.Failed()) {
410
0
        outer->MaybeReject(rv);
411
0
        return;
412
0
      }
413
0
      nsTArray<RefPtr<ServiceWorkerRegistration>> regList;
414
0
      for (auto& desc : aDescList) {
415
0
        RefPtr<ServiceWorkerRegistration> reg =
416
0
          global->GetOrCreateServiceWorkerRegistration(desc);
417
0
        if (reg) {
418
0
          regList.AppendElement(std::move(reg));
419
0
        }
420
0
      }
421
0
      outer->MaybeResolve(regList);
422
0
    }, [self, outer] (ErrorResult& aRv) {
423
0
      outer->MaybeReject(aRv);
424
0
    });
425
0
426
0
  return outer.forget();
427
0
}
428
429
already_AddRefed<Promise>
430
ServiceWorkerContainer::GetRegistration(const nsAString& aURL,
431
                                        ErrorResult& aRv)
432
0
{
433
0
  nsIGlobalObject* global = GetGlobalIfValid(aRv, [](nsIDocument* aDoc) {
434
0
    nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
435
0
                                    NS_LITERAL_CSTRING("Service Workers"), aDoc,
436
0
                                    nsContentUtils::eDOM_PROPERTIES,
437
0
                                    "ServiceWorkerGetRegistrationStorageError");
438
0
  });
439
0
  if (aRv.Failed()) {
440
0
    return nullptr;
441
0
  }
442
0
443
0
  Maybe<ClientInfo> clientInfo = global->GetClientInfo();
444
0
  if (clientInfo.isNothing()) {
445
0
    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
446
0
    return nullptr;
447
0
  }
448
0
449
0
  nsCOMPtr<nsIURI> baseURI = GetBaseURIFromGlobal(global, aRv);
450
0
  if (aRv.Failed()) {
451
0
    return nullptr;
452
0
  }
453
0
454
0
  nsCOMPtr<nsIURI> uri;
455
0
  aRv = NS_NewURI(getter_AddRefs(uri), aURL, nullptr, baseURI);
456
0
  if (aRv.Failed()) {
457
0
    return nullptr;
458
0
  }
459
0
460
0
  nsCString spec;
461
0
  aRv = uri->GetSpec(spec);
462
0
  if (aRv.Failed()) {
463
0
    return nullptr;
464
0
  }
465
0
466
0
  RefPtr<Promise> outer = Promise::Create(global, aRv);
467
0
  if (aRv.Failed()) {
468
0
    return nullptr;
469
0
  }
470
0
471
0
  RefPtr<ServiceWorkerContainer> self = this;
472
0
473
0
  mInner->GetRegistration(clientInfo.ref(), spec,
474
0
    [self, outer] (const ServiceWorkerRegistrationDescriptor& aDescriptor) {
475
0
      ErrorResult rv;
476
0
      nsIGlobalObject* global = self->GetGlobalIfValid(rv);
477
0
      if (rv.Failed()) {
478
0
        outer->MaybeReject(rv);
479
0
        return;
480
0
      }
481
0
      RefPtr<ServiceWorkerRegistration> reg =
482
0
        global->GetOrCreateServiceWorkerRegistration(aDescriptor);
483
0
      outer->MaybeResolve(reg);
484
0
    }, [self, outer] (ErrorResult& aRv) {
485
0
      if (!aRv.Failed()) {
486
0
        Unused << self->GetGlobalIfValid(aRv);
487
0
        if (!aRv.Failed()) {
488
0
          outer->MaybeResolveWithUndefined();
489
0
          return;
490
0
        }
491
0
      }
492
0
      outer->MaybeReject(aRv);
493
0
    });
494
0
495
0
  return outer.forget();
496
0
}
497
498
Promise*
499
ServiceWorkerContainer::GetReady(ErrorResult& aRv)
500
0
{
501
0
  if (mReadyPromise) {
502
0
    return mReadyPromise;
503
0
  }
504
0
505
0
  nsIGlobalObject* global = GetGlobalIfValid(aRv);
506
0
  if (aRv.Failed()) {
507
0
    return nullptr;
508
0
  }
509
0
  MOZ_DIAGNOSTIC_ASSERT(global);
510
0
511
0
  Maybe<ClientInfo> clientInfo(global->GetClientInfo());
512
0
  if (clientInfo.isNothing()) {
513
0
    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
514
0
    return nullptr;
515
0
  }
516
0
517
0
  mReadyPromise = Promise::Create(global, aRv);
518
0
  if (aRv.Failed()) {
519
0
    return nullptr;
520
0
  }
521
0
522
0
  RefPtr<ServiceWorkerContainer> self = this;
523
0
  RefPtr<Promise> outer = mReadyPromise;
524
0
525
0
  mInner->GetReady(clientInfo.ref(),
526
0
    [self, outer] (const ServiceWorkerRegistrationDescriptor& aDescriptor) {
527
0
      ErrorResult rv;
528
0
      nsIGlobalObject* global = self->GetGlobalIfValid(rv);
529
0
      if (rv.Failed()) {
530
0
        outer->MaybeReject(rv);
531
0
        return;
532
0
      }
533
0
      RefPtr<ServiceWorkerRegistration> reg =
534
0
        global->GetOrCreateServiceWorkerRegistration(aDescriptor);
535
0
      NS_ENSURE_TRUE_VOID(reg);
536
0
537
0
      // Don't resolve the ready promise until the registration has
538
0
      // reached the right version.  This ensures that the active
539
0
      // worker property is set correctly on the registration.
540
0
      reg->WhenVersionReached(aDescriptor.Version(),
541
0
        [outer, reg] (bool aResult) {
542
0
          outer->MaybeResolve(reg);
543
0
        });
544
0
    }, [self, outer] (ErrorResult& aRv) {
545
0
      outer->MaybeReject(aRv);
546
0
    });
547
0
548
0
  return mReadyPromise;
549
0
}
550
551
// Testing only.
552
void
553
ServiceWorkerContainer::GetScopeForUrl(const nsAString& aUrl,
554
                                       nsString& aScope,
555
                                       ErrorResult& aRv)
556
0
{
557
0
  nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
558
0
  if (!swm) {
559
0
    aRv.Throw(NS_ERROR_FAILURE);
560
0
    return;
561
0
  }
562
0
563
0
  nsCOMPtr<nsPIDOMWindowInner> window = GetOwner();
564
0
  if (NS_WARN_IF(!window)) {
565
0
    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
566
0
    return;
567
0
  }
568
0
569
0
  nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
570
0
  if (NS_WARN_IF(!doc)) {
571
0
    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
572
0
    return;
573
0
  }
574
0
575
0
  aRv = swm->GetScopeForUrl(doc->NodePrincipal(),
576
0
                            aUrl, aScope);
577
0
}
578
579
nsIGlobalObject*
580
ServiceWorkerContainer::GetGlobalIfValid(ErrorResult& aRv,
581
                                         const std::function<void(nsIDocument*)>&& aStorageFailureCB) const
582
0
{
583
0
  // For now we require a window since ServiceWorkerContainer is
584
0
  // not exposed on worker globals yet.  The main thing we need
585
0
  // to fix here to support that is the storage access check via
586
0
  // the nsIGlobalObject.
587
0
  nsPIDOMWindowInner* window = GetOwner();
588
0
  if (NS_WARN_IF(!window)) {
589
0
    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
590
0
    return nullptr;
591
0
  }
592
0
593
0
  nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
594
0
  if (NS_WARN_IF(!doc)) {
595
0
    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
596
0
    return nullptr;
597
0
  }
598
0
599
0
  // Don't allow a service worker to access service worker registrations
600
0
  // from a window with storage disabled.  If these windows can access
601
0
  // the registration it increases the chance they can bypass the storage
602
0
  // block via postMessage(), etc.
603
0
  auto storageAllowed = nsContentUtils::StorageAllowedForWindow(window);
604
0
  if (NS_WARN_IF(storageAllowed != nsContentUtils::StorageAccess::eAllow)) {
605
0
    if (aStorageFailureCB) {
606
0
      aStorageFailureCB(doc);
607
0
    }
608
0
    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
609
0
    return nullptr;
610
0
  }
611
0
612
0
  // Don't allow service workers when the document is chrome.
613
0
  if (NS_WARN_IF(nsContentUtils::IsSystemPrincipal(doc->NodePrincipal()))) {
614
0
    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
615
0
    return nullptr;
616
0
  }
617
0
618
0
  return window->AsGlobal();
619
0
}
620
621
} // namespace dom
622
} // namespace mozilla