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/. */
7 #include "ServiceWorkerScriptCache.h"
9 #include "js/Array.h" // JS::GetArrayLength
10 #include "js/PropertyAndElement.h" // JS_GetElement
11 #include "js/Utility.h" // JS::FreePolicy
12 #include "mozilla/TaskQueue.h"
13 #include "mozilla/Unused.h"
14 #include "mozilla/UniquePtr.h"
15 #include "mozilla/dom/CacheBinding.h"
16 #include "mozilla/dom/cache/CacheStorage.h"
17 #include "mozilla/dom/cache/Cache.h"
18 #include "mozilla/dom/Promise.h"
19 #include "mozilla/dom/PromiseWorkerProxy.h"
20 #include "mozilla/dom/ScriptLoader.h"
21 #include "mozilla/dom/WorkerCommon.h"
22 #include "mozilla/ipc/BackgroundUtils.h"
23 #include "mozilla/ipc/PBackgroundSharedTypes.h"
24 #include "mozilla/net/CookieJarSettings.h"
25 #include "mozilla/ScopeExit.h"
26 #include "mozilla/StaticPrefs_extensions.h"
27 #include "nsICacheInfoChannel.h"
28 #include "nsIHttpChannel.h"
29 #include "nsIStreamLoader.h"
30 #include "nsIThreadRetargetableRequest.h"
31 #include "nsIUUIDGenerator.h"
32 #include "nsIXPConnect.h"
34 #include "nsIInputStreamPump.h"
35 #include "nsIPrincipal.h"
36 #include "nsIScriptSecurityManager.h"
37 #include "nsContentUtils.h"
38 #include "nsNetUtil.h"
39 #include "ServiceWorkerManager.h"
40 #include "nsStringStream.h"
42 using mozilla::dom::cache::Cache
;
43 using mozilla::dom::cache::CacheStorage
;
44 using mozilla::ipc::PrincipalInfo
;
46 namespace mozilla::dom::serviceWorkerScriptCache
{
50 already_AddRefed
<CacheStorage
> CreateCacheStorage(JSContext
* aCx
,
51 nsIPrincipal
* aPrincipal
,
53 MOZ_ASSERT(NS_IsMainThread());
54 MOZ_ASSERT(aPrincipal
);
56 nsIXPConnect
* xpc
= nsContentUtils::XPConnect();
57 MOZ_ASSERT(xpc
, "This should never be null!");
58 JS::Rooted
<JSObject
*> sandbox(aCx
);
59 aRv
= xpc
->CreateSandbox(aCx
, aPrincipal
, sandbox
.address());
60 if (NS_WARN_IF(aRv
.Failed())) {
64 // This is called when the JSContext is not in a realm, so CreateSandbox
65 // returned an unwrapped global.
66 MOZ_ASSERT(JS_IsGlobalObject(sandbox
));
68 nsCOMPtr
<nsIGlobalObject
> sandboxGlobalObject
= xpc::NativeGlobal(sandbox
);
69 if (!sandboxGlobalObject
) {
70 aRv
.Throw(NS_ERROR_FAILURE
);
74 // We assume private browsing is not enabled here. The ScriptLoader
75 // explicitly fails for private browsing so there should never be
76 // a service worker running in private browsing mode. Therefore if
77 // we are purging scripts or running a comparison algorithm we cannot
78 // be in private browsing.
80 // Also, bypass the CacheStorage trusted origin checks. The ServiceWorker
81 // has validated the origin prior to this point. All the information
82 // to revalidate is not available now.
83 return CacheStorage::CreateOnMainThread(cache::CHROME_ONLY_NAMESPACE
,
84 sandboxGlobalObject
, aPrincipal
,
85 true /* force trusted origin */, aRv
);
91 // This class downloads a URL from the network, compare the downloaded script
92 // with an existing cache if provided, and report to CompareManager via calling
93 // ComparisonFinished().
94 class CompareNetwork final
: public nsIStreamLoaderObserver
,
95 public nsIRequestObserver
{
98 NS_DECL_NSISTREAMLOADEROBSERVER
99 NS_DECL_NSIREQUESTOBSERVER
101 CompareNetwork(CompareManager
* aManager
,
102 ServiceWorkerRegistrationInfo
* aRegistration
,
104 : mManager(aManager
),
105 mRegistration(aRegistration
),
106 mInternalHeaders(new InternalHeaders()),
107 mLoadFlags(nsIChannel::LOAD_BYPASS_SERVICE_WORKER
),
108 mState(WaitingForInitialization
),
109 mNetworkResult(NS_OK
),
111 mIsMainScript(aIsMainScript
),
112 mIsFromCache(false) {
113 MOZ_ASSERT(aManager
);
114 MOZ_ASSERT(NS_IsMainThread());
117 nsresult
Initialize(nsIPrincipal
* aPrincipal
, const nsAString
& aURL
,
118 Cache
* const aCache
);
122 void NetworkFinish(nsresult aRv
);
124 void CacheFinish(nsresult aRv
);
126 const nsString
& URL() const {
127 MOZ_ASSERT(NS_IsMainThread());
131 const nsString
& Buffer() const {
132 MOZ_ASSERT(NS_IsMainThread());
136 const ChannelInfo
& GetChannelInfo() const { return mChannelInfo
; }
138 already_AddRefed
<InternalHeaders
> GetInternalHeaders() const {
139 RefPtr
<InternalHeaders
> internalHeaders
= mInternalHeaders
;
140 return internalHeaders
.forget();
143 UniquePtr
<PrincipalInfo
> TakePrincipalInfo() {
144 return std::move(mPrincipalInfo
);
147 bool Succeeded() const { return NS_SUCCEEDED(mNetworkResult
); }
149 const nsTArray
<nsCString
>& URLList() const { return mURLList
; }
153 MOZ_ASSERT(NS_IsMainThread());
159 nsresult
SetPrincipalInfo(nsIChannel
* aChannel
);
161 RefPtr
<CompareManager
> mManager
;
162 RefPtr
<CompareCache
> mCC
;
163 RefPtr
<ServiceWorkerRegistrationInfo
> mRegistration
;
165 nsCOMPtr
<nsIChannel
> mChannel
;
168 ChannelInfo mChannelInfo
;
169 RefPtr
<InternalHeaders
> mInternalHeaders
;
170 UniquePtr
<PrincipalInfo
> mPrincipalInfo
;
171 nsTArray
<nsCString
> mURLList
;
174 nsLoadFlags mLoadFlags
;
177 WaitingForInitialization
,
178 WaitingForBothFinished
,
179 WaitingForNetworkFinished
,
180 WaitingForCacheFinished
,
184 nsresult mNetworkResult
;
185 nsresult mCacheResult
;
187 const bool mIsMainScript
;
191 NS_IMPL_ISUPPORTS(CompareNetwork
, nsIStreamLoaderObserver
, nsIRequestObserver
)
193 // This class gets a cached Response from the CacheStorage and then it calls
194 // CacheFinish() in the CompareNetwork.
195 class CompareCache final
: public PromiseNativeHandler
,
196 public nsIStreamLoaderObserver
{
199 NS_DECL_NSISTREAMLOADEROBSERVER
201 explicit CompareCache(CompareNetwork
* aCN
)
202 : mCN(aCN
), mState(WaitingForInitialization
), mInCache(false) {
204 MOZ_ASSERT(NS_IsMainThread());
207 nsresult
Initialize(Cache
* const aCache
, const nsAString
& aURL
);
209 void Finish(nsresult aStatus
, bool aInCache
);
213 virtual void ResolvedCallback(JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
,
214 ErrorResult
& aRv
) override
;
216 virtual void RejectedCallback(JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
,
217 ErrorResult
& aRv
) override
;
219 const nsString
& Buffer() const {
220 MOZ_ASSERT(NS_IsMainThread());
224 bool InCache() { return mInCache
; }
227 ~CompareCache() { MOZ_ASSERT(NS_IsMainThread()); }
229 void ManageValueResult(JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
);
231 RefPtr
<CompareNetwork
> mCN
;
232 nsCOMPtr
<nsIInputStreamPump
> mPump
;
238 WaitingForInitialization
,
246 NS_IMPL_ISUPPORTS(CompareCache
, nsIStreamLoaderObserver
)
248 class CompareManager final
: public PromiseNativeHandler
{
252 explicit CompareManager(ServiceWorkerRegistrationInfo
* aRegistration
,
253 CompareCallback
* aCallback
)
254 : mRegistration(aRegistration
),
255 mCallback(aCallback
),
256 mLoadFlags(nsIChannel::LOAD_BYPASS_SERVICE_WORKER
),
257 mState(WaitingForInitialization
),
259 mOnFailure(OnFailure::DoNothing
),
260 mAreScriptsEqual(true) {
261 MOZ_ASSERT(NS_IsMainThread());
262 MOZ_ASSERT(aRegistration
);
265 nsresult
Initialize(nsIPrincipal
* aPrincipal
, const nsAString
& aURL
,
266 const nsAString
& aCacheName
);
268 void ResolvedCallback(JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
,
269 ErrorResult
& aRv
) override
;
271 void RejectedCallback(JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
,
272 ErrorResult
& aRv
) override
;
274 CacheStorage
* CacheStorage_() {
275 MOZ_ASSERT(NS_IsMainThread());
276 MOZ_ASSERT(mCacheStorage
);
277 return mCacheStorage
;
280 void ComparisonFinished(nsresult aStatus
, bool aIsMainScript
, bool aIsEqual
,
281 const nsACString
& aMaxScope
, nsLoadFlags aLoadFlags
) {
282 MOZ_ASSERT(NS_IsMainThread());
283 if (mState
== Finished
) {
287 MOZ_DIAGNOSTIC_ASSERT(mState
== WaitingForScriptOrComparisonResult
);
289 if (NS_WARN_IF(NS_FAILED(aStatus
))) {
294 mAreScriptsEqual
= mAreScriptsEqual
&& aIsEqual
;
297 mMaxScope
= aMaxScope
;
298 mLoadFlags
= aLoadFlags
;
301 // Check whether all CompareNetworks finished their jobs.
302 MOZ_DIAGNOSTIC_ASSERT(mPendingCount
> 0);
303 if (--mPendingCount
) {
307 if (mAreScriptsEqual
) {
308 MOZ_ASSERT(mCallback
);
309 mCallback
->ComparisonResult(aStatus
, true /* aSameScripts */, mOnFailure
,
310 u
""_ns
, mMaxScope
, mLoadFlags
);
315 // Write to Cache so ScriptLoader reads succeed.
316 WriteNetworkBufferToNewCache();
321 MOZ_ASSERT(NS_IsMainThread());
322 MOZ_ASSERT(mCNList
.Length() == 0);
325 void Fail(nsresult aStatus
);
329 nsresult
FetchScript(const nsAString
& aURL
, bool aIsMainScript
,
330 Cache
* const aCache
= nullptr) {
331 MOZ_ASSERT(NS_IsMainThread());
333 MOZ_DIAGNOSTIC_ASSERT(mState
== WaitingForInitialization
||
334 mState
== WaitingForScriptOrComparisonResult
);
336 RefPtr
<CompareNetwork
> cn
=
337 new CompareNetwork(this, mRegistration
, aIsMainScript
);
338 mCNList
.AppendElement(cn
);
341 nsresult rv
= cn
->Initialize(mPrincipal
, aURL
, aCache
);
342 if (NS_WARN_IF(NS_FAILED(rv
))) {
349 void ManageOldCache(JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
) {
350 MOZ_DIAGNOSTIC_ASSERT(mState
== WaitingForExistingOpen
);
352 // RAII Cleanup when fails.
353 nsresult rv
= NS_ERROR_FAILURE
;
354 auto guard
= MakeScopeExit([&] { Fail(rv
); });
356 if (NS_WARN_IF(!aValue
.isObject())) {
360 MOZ_ASSERT(!mOldCache
);
361 JS::Rooted
<JSObject
*> obj(aCx
, &aValue
.toObject());
362 if (NS_WARN_IF(!obj
) ||
363 NS_WARN_IF(NS_FAILED(UNWRAP_OBJECT(Cache
, obj
, mOldCache
)))) {
367 Optional
<RequestOrUSVString
> request
;
368 CacheQueryOptions options
;
370 RefPtr
<Promise
> promise
= mOldCache
->Keys(aCx
, request
, options
, error
);
371 if (NS_WARN_IF(error
.Failed())) {
372 // No exception here because there are no ReadableStreams involved here.
373 MOZ_ASSERT(!error
.IsJSException());
374 rv
= error
.StealNSResult();
378 mState
= WaitingForExistingKeys
;
379 promise
->AppendNativeHandler(this);
383 void ManageOldKeys(JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
) {
384 MOZ_DIAGNOSTIC_ASSERT(mState
== WaitingForExistingKeys
);
386 // RAII Cleanup when fails.
387 nsresult rv
= NS_ERROR_FAILURE
;
388 auto guard
= MakeScopeExit([&] { Fail(rv
); });
390 if (NS_WARN_IF(!aValue
.isObject())) {
394 JS::Rooted
<JSObject
*> obj(aCx
, &aValue
.toObject());
395 if (NS_WARN_IF(!obj
)) {
400 if (!JS::GetArrayLength(aCx
, obj
, &len
)) {
404 // Fetch and compare the source scripts.
405 MOZ_ASSERT(mPendingCount
== 0);
407 mState
= WaitingForScriptOrComparisonResult
;
409 bool hasMainScript
= false;
410 AutoTArray
<nsString
, 8> urlList
;
412 // Extract the list of URLs in the old cache.
413 for (uint32_t i
= 0; i
< len
; ++i
) {
414 JS::Rooted
<JS::Value
> val(aCx
);
415 if (NS_WARN_IF(!JS_GetElement(aCx
, obj
, i
, &val
)) ||
416 NS_WARN_IF(!val
.isObject())) {
421 JS::Rooted
<JSObject
*> requestObj(aCx
, &val
.toObject());
422 if (NS_WARN_IF(NS_FAILED(UNWRAP_OBJECT(Request
, &requestObj
, request
)))) {
427 request
->GetUrl(url
);
429 if (!hasMainScript
&& url
== mURL
) {
430 hasMainScript
= true;
433 urlList
.AppendElement(url
);
436 // If the main script is missing, then something has gone wrong. We
437 // will try to continue with the update process to trigger a new
438 // installation. If that fails, however, then uninstall the registration
439 // because it is broken in a way that cannot be fixed.
440 if (!hasMainScript
) {
441 mOnFailure
= OnFailure::Uninstall
;
444 // Always make sure to fetch the main script. If the old cache has
445 // no entries or the main script entry is missing, then the loop below
446 // may not trigger it. This should not really happen, but we handle it
447 // gracefully if it does occur. Its possible the bad cache state is due
448 // to a crash or shutdown during an update, etc.
449 rv
= FetchScript(mURL
, true /* aIsMainScript */, mOldCache
);
450 if (NS_WARN_IF(NS_FAILED(rv
))) {
454 for (const auto& url
: urlList
) {
455 // We explicitly start the fetch for the main script above.
460 rv
= FetchScript(url
, false /* aIsMainScript */, mOldCache
);
461 if (NS_WARN_IF(NS_FAILED(rv
))) {
469 void ManageNewCache(JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
) {
470 MOZ_DIAGNOSTIC_ASSERT(mState
== WaitingForOpen
);
472 // RAII Cleanup when fails.
473 nsresult rv
= NS_ERROR_FAILURE
;
474 auto guard
= MakeScopeExit([&] { Fail(rv
); });
476 if (NS_WARN_IF(!aValue
.isObject())) {
480 JS::Rooted
<JSObject
*> obj(aCx
, &aValue
.toObject());
481 if (NS_WARN_IF(!obj
)) {
485 Cache
* cache
= nullptr;
486 rv
= UNWRAP_OBJECT(Cache
, &obj
, cache
);
487 if (NS_WARN_IF(NS_FAILED(rv
))) {
492 RefPtr
<Cache
> kungfuDeathGrip
= cache
;
494 MOZ_ASSERT(mPendingCount
== 0);
495 for (uint32_t i
= 0; i
< mCNList
.Length(); ++i
) {
496 // We bail out immediately when something goes wrong.
497 rv
= WriteToCache(aCx
, cache
, mCNList
[i
]);
498 if (NS_WARN_IF(NS_FAILED(rv
))) {
503 mState
= WaitingForPut
;
507 void WriteNetworkBufferToNewCache() {
508 MOZ_ASSERT(NS_IsMainThread());
509 MOZ_ASSERT(mCNList
.Length() != 0);
510 MOZ_ASSERT(mCacheStorage
);
511 MOZ_ASSERT(mNewCacheName
.IsEmpty());
514 result
= serviceWorkerScriptCache::GenerateCacheName(mNewCacheName
);
515 if (NS_WARN_IF(result
.Failed())) {
516 MOZ_ASSERT(!result
.IsErrorWithMessage());
517 Fail(result
.StealNSResult());
521 RefPtr
<Promise
> cacheOpenPromise
=
522 mCacheStorage
->Open(mNewCacheName
, result
);
523 if (NS_WARN_IF(result
.Failed())) {
524 MOZ_ASSERT(!result
.IsErrorWithMessage());
525 Fail(result
.StealNSResult());
529 mState
= WaitingForOpen
;
530 cacheOpenPromise
->AppendNativeHandler(this);
533 nsresult
WriteToCache(JSContext
* aCx
, Cache
* aCache
, CompareNetwork
* aCN
) {
534 MOZ_ASSERT(NS_IsMainThread());
537 MOZ_DIAGNOSTIC_ASSERT(mState
== WaitingForOpen
);
539 // We don't have to save any information from a failed CompareNetwork.
540 if (!aCN
->Succeeded()) {
544 nsCOMPtr
<nsIInputStream
> body
;
545 nsresult rv
= NS_NewCStringInputStream(
546 getter_AddRefs(body
), NS_ConvertUTF16toUTF8(aCN
->Buffer()));
547 if (NS_WARN_IF(NS_FAILED(rv
))) {
551 SafeRefPtr
<InternalResponse
> ir
=
552 MakeSafeRefPtr
<InternalResponse
>(200, "OK"_ns
);
553 ir
->SetBody(body
, aCN
->Buffer().Length());
554 ir
->SetURLList(aCN
->URLList());
556 ir
->InitChannelInfo(aCN
->GetChannelInfo());
557 UniquePtr
<PrincipalInfo
> principalInfo
= aCN
->TakePrincipalInfo();
559 ir
->SetPrincipalInfo(std::move(principalInfo
));
562 RefPtr
<InternalHeaders
> internalHeaders
= aCN
->GetInternalHeaders();
563 ir
->Headers()->Fill(*(internalHeaders
.get()), IgnoreErrors());
565 RefPtr
<Response
> response
=
566 new Response(aCache
->GetGlobalObject(), std::move(ir
), nullptr);
568 RequestOrUSVString request
;
569 request
.SetAsUSVString().ShareOrDependUpon(aCN
->URL());
571 // For now we have to wait until the Put Promise is fulfilled before we can
572 // continue since Cache does not yet support starting a read that is being
575 RefPtr
<Promise
> cachePromise
= aCache
->Put(aCx
, request
, *response
, result
);
576 result
.WouldReportJSException();
577 if (NS_WARN_IF(result
.Failed())) {
578 // No exception here because there are no ReadableStreams involved here.
579 MOZ_ASSERT(!result
.IsJSException());
580 MOZ_ASSERT(!result
.IsErrorWithMessage());
581 return result
.StealNSResult();
585 cachePromise
->AppendNativeHandler(this);
589 RefPtr
<ServiceWorkerRegistrationInfo
> mRegistration
;
590 RefPtr
<CompareCallback
> mCallback
;
591 RefPtr
<CacheStorage
> mCacheStorage
;
593 nsTArray
<RefPtr
<CompareNetwork
>> mCNList
;
596 RefPtr
<nsIPrincipal
> mPrincipal
;
598 // Used for the old cache where saves the old source scripts.
599 RefPtr
<Cache
> mOldCache
;
601 // Only used if the network script has changed and needs to be cached.
602 nsString mNewCacheName
;
605 nsLoadFlags mLoadFlags
;
608 WaitingForInitialization
,
609 WaitingForExistingOpen
,
610 WaitingForExistingKeys
,
611 WaitingForScriptOrComparisonResult
,
617 uint32_t mPendingCount
;
618 OnFailure mOnFailure
;
619 bool mAreScriptsEqual
;
622 NS_IMPL_ISUPPORTS0(CompareManager
)
624 nsresult
CompareNetwork::Initialize(nsIPrincipal
* aPrincipal
,
625 const nsAString
& aURL
,
626 Cache
* const aCache
) {
627 MOZ_ASSERT(aPrincipal
);
628 MOZ_ASSERT(NS_IsMainThread());
630 nsCOMPtr
<nsIURI
> uri
;
631 nsresult rv
= NS_NewURI(getter_AddRefs(uri
), aURL
);
632 if (NS_WARN_IF(NS_FAILED(rv
))) {
637 mURLList
.AppendElement(NS_ConvertUTF16toUTF8(mURL
));
639 nsCOMPtr
<nsILoadGroup
> loadGroup
;
640 rv
= NS_NewLoadGroup(getter_AddRefs(loadGroup
), aPrincipal
);
641 if (NS_WARN_IF(NS_FAILED(rv
))) {
645 // Update LoadFlags for propagating to ServiceWorkerInfo.
646 mLoadFlags
= nsIChannel::LOAD_BYPASS_SERVICE_WORKER
;
648 ServiceWorkerUpdateViaCache uvc
= mRegistration
->GetUpdateViaCache();
649 if (uvc
== ServiceWorkerUpdateViaCache::None
||
650 (uvc
== ServiceWorkerUpdateViaCache::Imports
&& mIsMainScript
)) {
651 mLoadFlags
|= nsIRequest::VALIDATE_ALWAYS
;
654 if (mRegistration
->IsLastUpdateCheckTimeOverOneDay()) {
655 mLoadFlags
|= nsIRequest::LOAD_BYPASS_CACHE
;
658 // Different settings are needed for fetching imported scripts, since they
659 // might be cross-origin scripts.
661 mIsMainScript
? nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED
662 : nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT
;
664 nsContentPolicyType contentPolicyType
=
665 mIsMainScript
? nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER
666 : nsIContentPolicy::TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS
;
668 // Create a new cookieJarSettings.
669 nsCOMPtr
<nsICookieJarSettings
> cookieJarSettings
=
670 mozilla::net::CookieJarSettings::Create(aPrincipal
);
672 // Populate the partitionKey by using the given prinicpal. The ServiceWorkers
673 // are using the foreign partitioned principal, so we can get the partitionKey
674 // from it and the partitionKey will only exist if it's in the third-party
675 // context. In first-party context, we can still use the uri to set the
677 if (!aPrincipal
->OriginAttributesRef().mPartitionKey
.IsEmpty()) {
678 net::CookieJarSettings::Cast(cookieJarSettings
)
679 ->SetPartitionKey(aPrincipal
->OriginAttributesRef().mPartitionKey
);
681 net::CookieJarSettings::Cast(cookieJarSettings
)->SetPartitionKey(uri
);
684 // Note that because there is no "serviceworker" RequestContext type, we can
685 // use the TYPE_INTERNAL_SCRIPT content policy types when loading a service
687 rv
= NS_NewChannel(getter_AddRefs(mChannel
), uri
, aPrincipal
, secFlags
,
688 contentPolicyType
, cookieJarSettings
,
689 nullptr /* aPerformanceStorage */, loadGroup
,
690 nullptr /* aCallbacks */, mLoadFlags
);
691 if (NS_WARN_IF(NS_FAILED(rv
))) {
695 nsCOMPtr
<nsIHttpChannel
> httpChannel
= do_QueryInterface(mChannel
);
697 // Spec says no redirects allowed for top-level SW scripts.
699 rv
= httpChannel
->SetRedirectionLimit(0);
700 MOZ_ASSERT(NS_SUCCEEDED(rv
));
703 rv
= httpChannel
->SetRequestHeader("Service-Worker"_ns
, "script"_ns
,
705 MOZ_ASSERT(NS_SUCCEEDED(rv
));
708 nsCOMPtr
<nsIStreamLoader
> loader
;
709 rv
= NS_NewStreamLoader(getter_AddRefs(loader
), this, this);
710 if (NS_WARN_IF(NS_FAILED(rv
))) {
714 rv
= mChannel
->AsyncOpen(loader
);
715 if (NS_WARN_IF(NS_FAILED(rv
))) {
719 // If we do have an existing cache to compare with.
721 mCC
= new CompareCache(this);
722 rv
= mCC
->Initialize(aCache
, aURL
);
723 if (NS_WARN_IF(NS_FAILED(rv
))) {
728 mState
= WaitingForBothFinished
;
732 mState
= WaitingForNetworkFinished
;
736 void CompareNetwork::Finish() {
737 if (mState
== Finished
) {
744 // mNetworkResult is prior to mCacheResult, since it's needed for reporting
745 // various errors to web content.
746 if (NS_FAILED(mNetworkResult
)) {
747 // An imported script could become offline, since it might no longer be
748 // needed by the new importing script. In that case, the importing script
749 // must be different, and thus, it's okay to report same script found here.
750 rv
= mIsMainScript
? mNetworkResult
: NS_OK
;
752 } else if (mCC
&& NS_FAILED(mCacheResult
)) {
754 } else { // Both passed.
755 same
= mCC
&& mCC
->InCache() && mCC
->Buffer().Equals(mBuffer
);
758 mManager
->ComparisonFinished(rv
, mIsMainScript
, same
, mMaxScope
, mLoadFlags
);
760 // We have done with the CompareCache.
764 void CompareNetwork::NetworkFinish(nsresult aRv
) {
765 MOZ_DIAGNOSTIC_ASSERT(mState
== WaitingForBothFinished
||
766 mState
== WaitingForNetworkFinished
);
768 mNetworkResult
= aRv
;
770 if (mState
== WaitingForBothFinished
) {
771 mState
= WaitingForCacheFinished
;
775 if (mState
== WaitingForNetworkFinished
) {
781 void CompareNetwork::CacheFinish(nsresult aRv
) {
782 MOZ_DIAGNOSTIC_ASSERT(mState
== WaitingForBothFinished
||
783 mState
== WaitingForCacheFinished
);
787 if (mState
== WaitingForBothFinished
) {
788 mState
= WaitingForNetworkFinished
;
792 if (mState
== WaitingForCacheFinished
) {
798 void CompareNetwork::Abort() {
799 MOZ_ASSERT(NS_IsMainThread());
801 if (mState
!= Finished
) {
804 MOZ_ASSERT(mChannel
);
805 mChannel
->CancelWithReason(NS_BINDING_ABORTED
, "CompareNetwork::Abort"_ns
);
816 CompareNetwork::OnStartRequest(nsIRequest
* aRequest
) {
817 MOZ_ASSERT(NS_IsMainThread());
819 if (mState
== Finished
) {
823 nsCOMPtr
<nsIChannel
> channel
= do_QueryInterface(aRequest
);
824 MOZ_ASSERT_IF(mIsMainScript
, channel
== mChannel
);
827 MOZ_ASSERT(!mChannelInfo
.IsInitialized());
828 mChannelInfo
.InitFromChannel(mChannel
);
830 nsresult rv
= SetPrincipalInfo(mChannel
);
831 if (NS_WARN_IF(NS_FAILED(rv
))) {
835 mInternalHeaders
->FillResponseHeaders(mChannel
);
837 nsCOMPtr
<nsICacheInfoChannel
> cacheChannel(do_QueryInterface(channel
));
839 cacheChannel
->IsFromCache(&mIsFromCache
);
845 nsresult
CompareNetwork::SetPrincipalInfo(nsIChannel
* aChannel
) {
846 nsIScriptSecurityManager
* ssm
= nsContentUtils::GetSecurityManager();
848 return NS_ERROR_FAILURE
;
851 nsCOMPtr
<nsIPrincipal
> channelPrincipal
;
852 nsresult rv
= ssm
->GetChannelResultPrincipal(
853 aChannel
, getter_AddRefs(channelPrincipal
));
854 if (NS_WARN_IF(NS_FAILED(rv
))) {
858 UniquePtr
<PrincipalInfo
> principalInfo
= MakeUnique
<PrincipalInfo
>();
859 rv
= PrincipalToPrincipalInfo(channelPrincipal
, principalInfo
.get());
861 if (NS_WARN_IF(NS_FAILED(rv
))) {
865 mPrincipalInfo
= std::move(principalInfo
);
870 CompareNetwork::OnStopRequest(nsIRequest
* aRequest
, nsresult aStatusCode
) {
871 // Nothing to do here!
876 CompareNetwork::OnStreamComplete(nsIStreamLoader
* aLoader
,
877 nsISupports
* aContext
, nsresult aStatus
,
878 uint32_t aLen
, const uint8_t* aString
) {
879 MOZ_ASSERT(NS_IsMainThread());
881 if (mState
== Finished
) {
885 nsresult rv
= NS_ERROR_FAILURE
;
886 auto guard
= MakeScopeExit([&] { NetworkFinish(rv
); });
888 if (NS_WARN_IF(NS_FAILED(aStatus
))) {
889 rv
= (aStatus
== NS_ERROR_REDIRECT_LOOP
) ? NS_ERROR_DOM_SECURITY_ERR
894 nsCOMPtr
<nsIRequest
> request
;
895 rv
= aLoader
->GetRequest(getter_AddRefs(request
));
896 if (NS_WARN_IF(NS_FAILED(rv
))) {
900 nsCOMPtr
<nsIChannel
> channel
= do_QueryInterface(request
);
901 MOZ_ASSERT(channel
, "How come we don't have any channel?");
903 nsCOMPtr
<nsIURI
> uri
;
904 channel
->GetOriginalURI(getter_AddRefs(uri
));
905 bool isExtension
= uri
->SchemeIs("moz-extension");
908 !StaticPrefs::extensions_backgroundServiceWorker_enabled_AtStartup()) {
909 // Return earlier with error is the worker script is a moz-extension url
910 // but the feature isn't enabled by prefs.
911 return NS_ERROR_FAILURE
;
915 // NOTE: trying to register any moz-extension use that doesn't ends
916 // with .js/.jsm/.mjs seems to be already completing with an error
917 // in aStatus and they never reach this point.
919 // TODO: look into avoid duplicated parts that could be shared with the HTTP
921 nsCOMPtr
<nsIURI
> channelURL
;
922 rv
= channel
->GetURI(getter_AddRefs(channelURL
));
923 if (NS_WARN_IF(NS_FAILED(rv
))) {
927 nsCString channelURLSpec
;
928 MOZ_ALWAYS_SUCCEEDS(channelURL
->GetSpec(channelURLSpec
));
930 // Append the final URL (which for an extension worker script is going to
931 // be a file or jar url).
932 MOZ_DIAGNOSTIC_ASSERT(!mURLList
.IsEmpty());
933 if (channelURLSpec
!= mURLList
[0]) {
934 mURLList
.AppendElement(channelURLSpec
);
937 UniquePtr
<char16_t
[], JS::FreePolicy
> buffer
;
940 rv
= ScriptLoader::ConvertToUTF16(channel
, aString
, aLen
, u
"UTF-8"_ns
,
941 nullptr, buffer
, len
);
942 if (NS_WARN_IF(NS_FAILED(rv
))) {
946 mBuffer
.Adopt(buffer
.release(), len
);
952 nsCOMPtr
<nsIHttpChannel
> httpChannel
= do_QueryInterface(request
);
954 // Main scripts cannot be redirected successfully, however extensions
955 // may successfuly redirect imported scripts to a moz-extension url
956 // (if listed in the web_accessible_resources manifest property).
958 // When the service worker is initially registered the imported scripts
959 // will be loaded from the child process (see dom/workers/ScriptLoader.cpp)
960 // and in that case this method will only be called for the main script.
962 // When a registered worker is loaded again (e.g. when the webpage calls
963 // the ServiceWorkerRegistration's update method):
965 // - both the main and imported scripts are loaded by the
966 // CompareManager::FetchScript
967 // - the update requests for the imported scripts will also be calling this
968 // method and we should expect scripts redirected to an extension script
969 // to have a null httpChannel.
971 // The request that triggers this method is:
973 // - the one that is coming from the network (which may be intercepted by
974 // WebRequest listeners in extensions and redirected to a web_accessible
975 // moz-extension url)
976 // - it will then be compared with a previous response that we may have
979 // When the next service worker update occurs, if the request (for an imported
980 // script) is not redirected by an extension the cache entry is invalidated
981 // and a network request is triggered for the import.
983 // Redirecting a service worker main script should fail before reaching this
985 // If a main script is somehow redirected, the diagnostic assert will crash
986 // in non-release builds. Release builds will return an explicit error.
987 MOZ_DIAGNOSTIC_ASSERT(!mIsMainScript
,
988 "Unexpected ServiceWorker main script redirected");
990 return NS_ERROR_UNEXPECTED
;
993 nsCOMPtr
<nsIPrincipal
> channelPrincipal
;
995 nsIScriptSecurityManager
* ssm
= nsContentUtils::GetSecurityManager();
997 return NS_ERROR_UNEXPECTED
;
1000 nsresult rv
= ssm
->GetChannelResultPrincipal(
1001 channel
, getter_AddRefs(channelPrincipal
));
1003 // An extension did redirect a non-MainScript request to a moz-extension url
1004 // (in that case the originalURL is the resolved jar URI and so we have to
1005 // look to the channel principal instead).
1006 if (channelPrincipal
->SchemeIs("moz-extension")) {
1007 UniquePtr
<char16_t
[], JS::FreePolicy
> buffer
;
1010 rv
= ScriptLoader::ConvertToUTF16(channel
, aString
, aLen
, u
"UTF-8"_ns
,
1011 nullptr, buffer
, len
);
1012 if (NS_WARN_IF(NS_FAILED(rv
))) {
1016 mBuffer
.Adopt(buffer
.release(), len
);
1021 // Make non-release and debug builds to crash if this happens and fail
1022 // explicitly on release builds.
1023 MOZ_DIAGNOSTIC_ASSERT(false,
1024 "ServiceWorker imported script redirected to an url "
1025 "with an unexpected scheme");
1026 return NS_ERROR_UNEXPECTED
;
1029 bool requestSucceeded
;
1030 rv
= httpChannel
->GetRequestSucceeded(&requestSucceeded
);
1031 if (NS_WARN_IF(NS_FAILED(rv
))) {
1035 if (NS_WARN_IF(!requestSucceeded
)) {
1036 // Get the stringified numeric status code, not statusText which could be
1037 // something misleading like OK for a 404.
1038 uint32_t status
= 0;
1039 Unused
<< httpChannel
->GetResponseStatus(
1040 &status
); // don't care if this fails, use 0.
1041 nsAutoString statusAsText
;
1042 statusAsText
.AppendInt(status
);
1044 ServiceWorkerManager::LocalizeAndReportToAllClients(
1045 mRegistration
->Scope(), "ServiceWorkerRegisterNetworkError",
1046 nsTArray
<nsString
>{NS_ConvertUTF8toUTF16(mRegistration
->Scope()),
1047 statusAsText
, mURL
});
1049 rv
= NS_ERROR_FAILURE
;
1053 // Note: we explicitly don't check for the return value here, because the
1054 // absence of the header is not an error condition.
1055 Unused
<< httpChannel
->GetResponseHeader("Service-Worker-Allowed"_ns
,
1058 // [9.2 Update]4.13, If response's cache state is not "local",
1059 // set registration's last update check time to the current time
1060 if (!mIsFromCache
) {
1061 mRegistration
->RefreshLastUpdateCheckTime();
1064 nsAutoCString mimeType
;
1065 rv
= httpChannel
->GetContentType(mimeType
);
1066 if (NS_WARN_IF(NS_FAILED(rv
))) {
1067 // We should only end up here if !mResponseHead in the channel. If headers
1068 // were received but no content type was specified, we'll be given
1069 // UNKNOWN_CONTENT_TYPE "application/x-unknown-content-type" and so fall
1070 // into the next case with its better error message.
1071 rv
= NS_ERROR_DOM_SECURITY_ERR
;
1075 if (mimeType
.IsEmpty() ||
1076 !nsContentUtils::IsJavascriptMIMEType(NS_ConvertUTF8toUTF16(mimeType
))) {
1077 ServiceWorkerManager::LocalizeAndReportToAllClients(
1078 mRegistration
->Scope(), "ServiceWorkerRegisterMimeTypeError2",
1079 nsTArray
<nsString
>{NS_ConvertUTF8toUTF16(mRegistration
->Scope()),
1080 NS_ConvertUTF8toUTF16(mimeType
), mURL
});
1081 rv
= NS_ERROR_DOM_SECURITY_ERR
;
1085 nsCOMPtr
<nsIURI
> channelURL
;
1086 rv
= httpChannel
->GetURI(getter_AddRefs(channelURL
));
1087 if (NS_WARN_IF(NS_FAILED(rv
))) {
1091 nsCString channelURLSpec
;
1092 MOZ_ALWAYS_SUCCEEDS(channelURL
->GetSpec(channelURLSpec
));
1094 // Append the final URL if its different from the original
1095 // request URL. This lets us note that a redirect occurred
1096 // even though we don't track every redirect URL here.
1097 MOZ_DIAGNOSTIC_ASSERT(!mURLList
.IsEmpty());
1098 if (channelURLSpec
!= mURLList
[0]) {
1099 mURLList
.AppendElement(channelURLSpec
);
1102 UniquePtr
<char16_t
[], JS::FreePolicy
> buffer
;
1105 rv
= ScriptLoader::ConvertToUTF16(httpChannel
, aString
, aLen
, u
"UTF-8"_ns
,
1106 nullptr, buffer
, len
);
1107 if (NS_WARN_IF(NS_FAILED(rv
))) {
1111 mBuffer
.Adopt(buffer
.release(), len
);
1117 nsresult
CompareCache::Initialize(Cache
* const aCache
, const nsAString
& aURL
) {
1118 MOZ_ASSERT(NS_IsMainThread());
1120 MOZ_DIAGNOSTIC_ASSERT(mState
== WaitingForInitialization
);
1122 // This JSContext will not end up executing JS code because here there are
1123 // no ReadableStreams involved.
1127 RequestOrUSVString request
;
1128 request
.SetAsUSVString().ShareOrDependUpon(aURL
);
1130 CacheQueryOptions params
;
1131 RefPtr
<Promise
> promise
= aCache
->Match(jsapi
.cx(), request
, params
, error
);
1132 if (NS_WARN_IF(error
.Failed())) {
1133 // No exception here because there are no ReadableStreams involved here.
1134 MOZ_ASSERT(!error
.IsJSException());
1136 return error
.StealNSResult();
1139 // Retrieve the script from aCache.
1140 mState
= WaitingForScript
;
1141 promise
->AppendNativeHandler(this);
1145 void CompareCache::Finish(nsresult aStatus
, bool aInCache
) {
1146 if (mState
!= Finished
) {
1148 mInCache
= aInCache
;
1149 mCN
->CacheFinish(aStatus
);
1153 void CompareCache::Abort() {
1154 MOZ_ASSERT(NS_IsMainThread());
1156 if (mState
!= Finished
) {
1160 mPump
->CancelWithReason(NS_BINDING_ABORTED
, "CompareCache::Abort"_ns
);
1167 CompareCache::OnStreamComplete(nsIStreamLoader
* aLoader
, nsISupports
* aContext
,
1168 nsresult aStatus
, uint32_t aLen
,
1169 const uint8_t* aString
) {
1170 MOZ_ASSERT(NS_IsMainThread());
1172 if (mState
== Finished
) {
1176 if (NS_WARN_IF(NS_FAILED(aStatus
))) {
1177 Finish(aStatus
, false);
1181 UniquePtr
<char16_t
[], JS::FreePolicy
> buffer
;
1184 nsresult rv
= ScriptLoader::ConvertToUTF16(nullptr, aString
, aLen
,
1185 u
"UTF-8"_ns
, nullptr, buffer
, len
);
1186 if (NS_WARN_IF(NS_FAILED(rv
))) {
1191 mBuffer
.Adopt(buffer
.release(), len
);
1193 Finish(NS_OK
, true);
1197 void CompareCache::ResolvedCallback(JSContext
* aCx
,
1198 JS::Handle
<JS::Value
> aValue
,
1200 MOZ_ASSERT(NS_IsMainThread());
1205 case WaitingForScript
:
1206 ManageValueResult(aCx
, aValue
);
1209 MOZ_CRASH("Unacceptable state.");
1213 void CompareCache::RejectedCallback(JSContext
* aCx
,
1214 JS::Handle
<JS::Value
> aValue
,
1216 MOZ_ASSERT(NS_IsMainThread());
1218 if (mState
!= Finished
) {
1219 Finish(NS_ERROR_FAILURE
, false);
1224 void CompareCache::ManageValueResult(JSContext
* aCx
,
1225 JS::Handle
<JS::Value
> aValue
) {
1226 MOZ_ASSERT(NS_IsMainThread());
1228 // The cache returns undefined if the object is not stored.
1229 if (aValue
.isUndefined()) {
1230 Finish(NS_OK
, false);
1234 MOZ_ASSERT(aValue
.isObject());
1236 JS::Rooted
<JSObject
*> obj(aCx
, &aValue
.toObject());
1237 if (NS_WARN_IF(!obj
)) {
1238 Finish(NS_ERROR_FAILURE
, false);
1242 Response
* response
= nullptr;
1243 nsresult rv
= UNWRAP_OBJECT(Response
, &obj
, response
);
1244 if (NS_WARN_IF(NS_FAILED(rv
))) {
1249 MOZ_ASSERT(response
->Ok());
1251 nsCOMPtr
<nsIInputStream
> inputStream
;
1252 response
->GetBody(getter_AddRefs(inputStream
));
1253 MOZ_ASSERT(inputStream
);
1256 rv
= NS_NewInputStreamPump(getter_AddRefs(mPump
), inputStream
.forget(),
1257 0, /* default segsize */
1258 0, /* default segcount */
1259 false, /* default closeWhenDone */
1260 GetMainThreadSerialEventTarget());
1261 if (NS_WARN_IF(NS_FAILED(rv
))) {
1266 nsCOMPtr
<nsIStreamLoader
> loader
;
1267 rv
= NS_NewStreamLoader(getter_AddRefs(loader
), this);
1268 if (NS_WARN_IF(NS_FAILED(rv
))) {
1273 rv
= mPump
->AsyncRead(loader
);
1274 if (NS_WARN_IF(NS_FAILED(rv
))) {
1280 nsCOMPtr
<nsIThreadRetargetableRequest
> rr
= do_QueryInterface(mPump
);
1282 nsCOMPtr
<nsIEventTarget
> sts
=
1283 do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID
);
1284 RefPtr
<TaskQueue
> queue
=
1285 TaskQueue::Create(sts
.forget(), "CompareCache STS Delivery Queue");
1286 rv
= rr
->RetargetDeliveryTo(queue
);
1287 if (NS_WARN_IF(NS_FAILED(rv
))) {
1295 nsresult
CompareManager::Initialize(nsIPrincipal
* aPrincipal
,
1296 const nsAString
& aURL
,
1297 const nsAString
& aCacheName
) {
1298 MOZ_ASSERT(NS_IsMainThread());
1299 MOZ_ASSERT(aPrincipal
);
1300 MOZ_ASSERT(mPendingCount
== 0);
1301 MOZ_DIAGNOSTIC_ASSERT(mState
== WaitingForInitialization
);
1303 // RAII Cleanup when fails.
1304 auto guard
= MakeScopeExit([&] { Cleanup(); });
1307 mPrincipal
= aPrincipal
;
1309 // Always create a CacheStorage since we want to write the network entry to
1310 // the cache even if there isn't an existing one.
1314 mCacheStorage
= CreateCacheStorage(jsapi
.cx(), aPrincipal
, result
);
1315 if (NS_WARN_IF(result
.Failed())) {
1316 MOZ_ASSERT(!result
.IsErrorWithMessage());
1317 return result
.StealNSResult();
1320 // If there is no existing cache, proceed to fetch the script directly.
1321 if (aCacheName
.IsEmpty()) {
1322 mState
= WaitingForScriptOrComparisonResult
;
1323 nsresult rv
= FetchScript(aURL
, true /* aIsMainScript */);
1324 if (NS_WARN_IF(NS_FAILED(rv
))) {
1332 // Open the cache saving the old source scripts.
1333 RefPtr
<Promise
> promise
= mCacheStorage
->Open(aCacheName
, result
);
1334 if (NS_WARN_IF(result
.Failed())) {
1335 MOZ_ASSERT(!result
.IsErrorWithMessage());
1336 return result
.StealNSResult();
1339 mState
= WaitingForExistingOpen
;
1340 promise
->AppendNativeHandler(this);
1346 // This class manages 4 promises if needed:
1347 // 1. Retrieve the Cache object by a given CacheName of OldCache.
1348 // 2. Retrieve the URLs saved in OldCache.
1349 // 3. Retrieve the Cache object of the NewCache for the newly created SW.
1350 // 4. Put the value in the cache.
1351 // For this reason we have mState to know what callback we are handling.
1352 void CompareManager::ResolvedCallback(JSContext
* aCx
,
1353 JS::Handle
<JS::Value
> aValue
,
1355 MOZ_ASSERT(NS_IsMainThread());
1356 MOZ_ASSERT(mCallback
);
1361 case WaitingForExistingOpen
:
1362 ManageOldCache(aCx
, aValue
);
1364 case WaitingForExistingKeys
:
1365 ManageOldKeys(aCx
, aValue
);
1367 case WaitingForOpen
:
1368 ManageNewCache(aCx
, aValue
);
1371 MOZ_DIAGNOSTIC_ASSERT(mPendingCount
> 0);
1372 if (--mPendingCount
== 0) {
1373 mCallback
->ComparisonResult(NS_OK
, false /* aIsEqual */, mOnFailure
,
1374 mNewCacheName
, mMaxScope
, mLoadFlags
);
1379 MOZ_DIAGNOSTIC_ASSERT(false);
1383 void CompareManager::RejectedCallback(JSContext
* aCx
,
1384 JS::Handle
<JS::Value
> aValue
,
1386 MOZ_ASSERT(NS_IsMainThread());
1390 case WaitingForExistingOpen
:
1391 NS_WARNING("Could not open the existing cache.");
1393 case WaitingForExistingKeys
:
1394 NS_WARNING("Could not get the existing URLs.");
1396 case WaitingForOpen
:
1397 NS_WARNING("Could not open cache.");
1400 NS_WARNING("Could not write to cache.");
1403 MOZ_DIAGNOSTIC_ASSERT(false);
1406 Fail(NS_ERROR_FAILURE
);
1409 void CompareManager::Fail(nsresult aStatus
) {
1410 MOZ_ASSERT(NS_IsMainThread());
1411 mCallback
->ComparisonResult(aStatus
, false /* aIsEqual */, mOnFailure
, u
""_ns
,
1416 void CompareManager::Cleanup() {
1417 MOZ_ASSERT(NS_IsMainThread());
1419 if (mState
!= Finished
) {
1422 MOZ_ASSERT(mCallback
);
1423 mCallback
= nullptr;
1425 // Abort and release CompareNetworks.
1426 for (uint32_t i
= 0; i
< mCNList
.Length(); ++i
) {
1427 mCNList
[i
]->Abort();
1435 nsresult
PurgeCache(nsIPrincipal
* aPrincipal
, const nsAString
& aCacheName
) {
1436 MOZ_ASSERT(NS_IsMainThread());
1437 MOZ_ASSERT(aPrincipal
);
1439 if (aCacheName
.IsEmpty()) {
1446 RefPtr
<CacheStorage
> cacheStorage
=
1447 CreateCacheStorage(jsapi
.cx(), aPrincipal
, rv
);
1448 if (NS_WARN_IF(rv
.Failed())) {
1449 return rv
.StealNSResult();
1452 // We use the ServiceWorker scope as key for the cacheStorage.
1453 RefPtr
<Promise
> promise
= cacheStorage
->Delete(aCacheName
, rv
);
1454 if (NS_WARN_IF(rv
.Failed())) {
1455 return rv
.StealNSResult();
1458 // Set [[PromiseIsHandled]] to ensure that if this promise gets rejected,
1459 // we don't end up reporting a rejected promise to the console.
1460 MOZ_ALWAYS_TRUE(promise
->SetAnyPromiseIsHandled());
1462 // We don't actually care about the result of the delete operation.
1466 nsresult
GenerateCacheName(nsAString
& aName
) {
1468 nsCOMPtr
<nsIUUIDGenerator
> uuidGenerator
=
1469 do_GetService("@mozilla.org/uuid-generator;1", &rv
);
1470 if (NS_WARN_IF(NS_FAILED(rv
))) {
1475 rv
= uuidGenerator
->GenerateUUIDInPlace(&id
);
1476 if (NS_WARN_IF(NS_FAILED(rv
))) {
1480 char chars
[NSID_LENGTH
];
1481 id
.ToProvidedString(chars
);
1483 // NSID_LENGTH counts the null terminator.
1484 aName
.AssignASCII(chars
, NSID_LENGTH
- 1);
1489 nsresult
Compare(ServiceWorkerRegistrationInfo
* aRegistration
,
1490 nsIPrincipal
* aPrincipal
, const nsAString
& aCacheName
,
1491 const nsAString
& aURL
, CompareCallback
* aCallback
) {
1492 MOZ_ASSERT(NS_IsMainThread());
1493 MOZ_ASSERT(aRegistration
);
1494 MOZ_ASSERT(aPrincipal
);
1495 MOZ_ASSERT(!aURL
.IsEmpty());
1496 MOZ_ASSERT(aCallback
);
1498 RefPtr
<CompareManager
> cm
= new CompareManager(aRegistration
, aCallback
);
1500 nsresult rv
= cm
->Initialize(aPrincipal
, aURL
, aCacheName
);
1501 if (NS_WARN_IF(NS_FAILED(rv
))) {
1508 } // namespace mozilla::dom::serviceWorkerScriptCache