mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-16 13:56:29 +00:00
Bug 1181887 Fall back to network if ServiceWorker script fails to load. r=ehsan r=khuey
This commit is contained in:
parent
422a1bbf1d
commit
55e3066722
@ -9,6 +9,7 @@ interface nsIArray;
|
||||
interface nsIDocument;
|
||||
interface nsIInterceptedChannel;
|
||||
interface nsIPrincipal;
|
||||
interface nsIRunnable;
|
||||
interface nsIURI;
|
||||
|
||||
[scriptable, uuid(52ee2c9d-ee87-4caf-9588-23ae77ff8798)]
|
||||
@ -33,7 +34,7 @@ interface nsIServiceWorkerInfo : nsISupports
|
||||
readonly attribute DOMString waitingCacheName;
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(ed1cbbf2-0400-4caa-8eb2-b09d21a94e20)]
|
||||
[scriptable, builtinclass, uuid(8d80dd18-597b-4378-b41e-768bfe48dd4f)]
|
||||
interface nsIServiceWorkerManager : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -93,8 +94,11 @@ interface nsIServiceWorkerManager : nsISupports
|
||||
|
||||
/*
|
||||
* Returns a ServiceWorker.
|
||||
* - aLoadFailedRunnable is an optional callback that will fire on main thread if
|
||||
* a ServiceWorker object is returned, but later fails to load for some reason.
|
||||
*/
|
||||
[noscript] nsISupports GetDocumentController(in nsIDOMWindow aWindow);
|
||||
[noscript] nsISupports GetDocumentController(in nsIDOMWindow aWindow,
|
||||
in nsIRunnable aLoadFailedRunnable);
|
||||
|
||||
/*
|
||||
* Clears ServiceWorker registrations from memory and disk for the specified
|
||||
|
@ -1729,6 +1729,7 @@ ScriptExecutorRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
if (NS_FAILED(loadInfo.mLoadResult)) {
|
||||
scriptloader::ReportLoadError(aCx, loadInfo.mURL, loadInfo.mLoadResult,
|
||||
false);
|
||||
aWorkerPrivate->MaybeDispatchLoadFailedRunnable();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -164,8 +164,13 @@ ServiceWorkerContainer::GetController()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// TODO: What should we do here if the ServiceWorker script fails to load?
|
||||
// In theory the DOM ServiceWorker object can exist without the worker
|
||||
// thread running, but it seems our design does not expect that.
|
||||
nsCOMPtr<nsISupports> serviceWorker;
|
||||
rv = swm->GetDocumentController(GetOwner(), getter_AddRefs(serviceWorker));
|
||||
rv = swm->GetDocumentController(GetOwner(),
|
||||
nullptr, // aLoadFailedRunnable
|
||||
getter_AddRefs(serviceWorker));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -1062,6 +1062,11 @@ public:
|
||||
MOZ_ASSERT(!data->mSetOfScopesBeingUpdated.Contains(mRegistration->mScope));
|
||||
data->mSetOfScopesBeingUpdated.Put(mRegistration->mScope, true);
|
||||
|
||||
// Call FailScopeUpdate on main thread if the SW script load fails below.
|
||||
nsCOMPtr<nsIRunnable> failRunnable = NS_NewRunnableMethodWithArgs
|
||||
<StorensRefPtrPassByPtr<ServiceWorkerManager>, nsCString>
|
||||
(this, &ServiceWorkerRegisterJob::FailScopeUpdate, swm, scopeKey);
|
||||
|
||||
MOZ_ASSERT(!mUpdateAndInstallInfo);
|
||||
mUpdateAndInstallInfo =
|
||||
new ServiceWorkerInfo(mRegistration, mRegistration->mScriptSpec,
|
||||
@ -1069,11 +1074,11 @@ public:
|
||||
nsRefPtr<ServiceWorker> serviceWorker;
|
||||
rv = swm->CreateServiceWorker(mRegistration->mPrincipal,
|
||||
mUpdateAndInstallInfo,
|
||||
failRunnable,
|
||||
getter_AddRefs(serviceWorker));
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
data->mSetOfScopesBeingUpdated.Remove(mRegistration->mScope);
|
||||
return Fail(NS_ERROR_DOM_ABORT_ERR);
|
||||
return FailScopeUpdate(swm, scopeKey);
|
||||
}
|
||||
|
||||
nsRefPtr<ServiceWorkerJob> upcasted = this;
|
||||
@ -1088,11 +1093,22 @@ public:
|
||||
jsapi.Init();
|
||||
bool ok = r->Dispatch(jsapi.cx());
|
||||
if (NS_WARN_IF(!ok)) {
|
||||
data->mSetOfScopesBeingUpdated.Remove(mRegistration->mScope);
|
||||
return Fail(NS_ERROR_DOM_ABORT_ERR);
|
||||
return FailScopeUpdate(swm, scopeKey);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FailScopeUpdate(ServiceWorkerManager* aSwm, const nsACString& aScopeKey)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aSwm);
|
||||
ServiceWorkerManager::RegistrationDataPerPrincipal* data;
|
||||
if (aSwm->mRegistrationInfos.Get(aScopeKey, &data)) {
|
||||
data->mSetOfScopesBeingUpdated.Remove(aScopeKey);
|
||||
}
|
||||
Fail(NS_ERROR_DOM_ABORT_ERR);
|
||||
}
|
||||
|
||||
// Public so our error handling code can use it.
|
||||
// Callers MUST hold a strong ref before calling this!
|
||||
void
|
||||
@ -1168,9 +1184,15 @@ public:
|
||||
|
||||
NS_DispatchToMainThread(upr);
|
||||
|
||||
// Call ContinueAfterInstallEvent(false, false) on main thread if the SW
|
||||
// script fails to load.
|
||||
nsCOMPtr<nsIRunnable> failRunnable = NS_NewRunnableMethodWithArgs<bool, bool>
|
||||
(this, &ServiceWorkerRegisterJob::ContinueAfterInstallEvent, false, false);
|
||||
|
||||
nsRefPtr<ServiceWorker> serviceWorker;
|
||||
rv = swm->CreateServiceWorker(mRegistration->mPrincipal,
|
||||
mRegistration->mInstallingWorker,
|
||||
failRunnable,
|
||||
getter_AddRefs(serviceWorker));
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
@ -1834,18 +1856,20 @@ ServiceWorkerRegistrationInfo::Activate()
|
||||
this);
|
||||
NS_DispatchToMainThread(controllerChangeRunnable);
|
||||
|
||||
nsCOMPtr<nsIRunnable> failRunnable =
|
||||
NS_NewRunnableMethodWithArg<bool>(this,
|
||||
&ServiceWorkerRegistrationInfo::FinishActivate,
|
||||
false /* success */);
|
||||
|
||||
MOZ_ASSERT(mActiveWorker);
|
||||
nsRefPtr<ServiceWorker> serviceWorker;
|
||||
nsresult rv =
|
||||
swm->CreateServiceWorker(mPrincipal,
|
||||
mActiveWorker,
|
||||
failRunnable,
|
||||
getter_AddRefs(serviceWorker));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
nsCOMPtr<nsIRunnable> r =
|
||||
NS_NewRunnableMethodWithArg<bool>(this,
|
||||
&ServiceWorkerRegistrationInfo::FinishActivate,
|
||||
false /* success */);
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(r)));
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(failRunnable)));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2227,7 +2251,7 @@ ServiceWorkerManager::SendPushEvent(const nsACString& aOriginAttributes,
|
||||
}
|
||||
|
||||
nsRefPtr<ServiceWorker> serviceWorker =
|
||||
CreateServiceWorkerForScope(attrs, aScope);
|
||||
CreateServiceWorkerForScope(attrs, aScope, nullptr /* failure runnable */);
|
||||
if (!serviceWorker) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -2262,7 +2286,7 @@ ServiceWorkerManager::SendPushSubscriptionChangeEvent(const nsACString& aOriginA
|
||||
}
|
||||
|
||||
nsRefPtr<ServiceWorker> serviceWorker =
|
||||
CreateServiceWorkerForScope(attrs, aScope);
|
||||
CreateServiceWorkerForScope(attrs, aScope, nullptr /* fail runnable */);
|
||||
if (!serviceWorker) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -2387,7 +2411,8 @@ ServiceWorkerManager::SendNotificationClickEvent(const nsACString& aOriginSuffix
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsRefPtr<ServiceWorker> serviceWorker = CreateServiceWorkerForScope(attrs, aScope);
|
||||
nsRefPtr<ServiceWorker> serviceWorker =
|
||||
CreateServiceWorkerForScope(attrs, aScope, nullptr);
|
||||
if (!serviceWorker) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -2525,7 +2550,8 @@ ServiceWorkerManager::CheckReadyPromise(nsPIDOMWindow* aWindow,
|
||||
|
||||
already_AddRefed<ServiceWorker>
|
||||
ServiceWorkerManager::CreateServiceWorkerForScope(const OriginAttributes& aOriginAttributes,
|
||||
const nsACString& aScope)
|
||||
const nsACString& aScope,
|
||||
nsIRunnable* aLoadFailedRunnable)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
@ -2547,6 +2573,7 @@ ServiceWorkerManager::CreateServiceWorkerForScope(const OriginAttributes& aOrigi
|
||||
nsRefPtr<ServiceWorker> sw;
|
||||
rv = CreateServiceWorker(registration->mPrincipal,
|
||||
registration->mActiveWorker,
|
||||
aLoadFailedRunnable,
|
||||
getter_AddRefs(sw));
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
@ -2827,6 +2854,7 @@ ServiceWorkerRegistrationInfo::FinishActivate(bool aSuccess)
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerManager::CreateServiceWorkerForWindow(nsPIDOMWindow* aWindow,
|
||||
ServiceWorkerInfo* aInfo,
|
||||
nsIRunnable* aLoadFailedRunnable,
|
||||
ServiceWorker** aServiceWorker)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
@ -2851,6 +2879,7 @@ ServiceWorkerManager::CreateServiceWorkerForWindow(nsPIDOMWindow* aWindow,
|
||||
MOZ_ASSERT(!aInfo->CacheName().IsEmpty());
|
||||
loadInfo.mServiceWorkerCacheName = aInfo->CacheName();
|
||||
loadInfo.mServiceWorkerID = aInfo->ID();
|
||||
loadInfo.mLoadFailedAsyncRunnable = aLoadFailedRunnable;
|
||||
|
||||
RuntimeService* rs = RuntimeService::GetOrCreateService();
|
||||
if (!rs) {
|
||||
@ -3418,9 +3447,13 @@ ServiceWorkerManager::GetServiceWorkerForScope(nsIDOMWindow* aWindow,
|
||||
return NS_ERROR_DOM_NOT_FOUND_ERR;
|
||||
}
|
||||
|
||||
// TODO: How should we handle async failure of SW load for getters? In
|
||||
// theory getting a handle to the DOM ServiceWorker object should not
|
||||
// require the worker thread to actually be running.
|
||||
nsRefPtr<ServiceWorker> serviceWorker;
|
||||
rv = CreateServiceWorkerForWindow(window,
|
||||
info,
|
||||
nullptr, // load failed runnable
|
||||
getter_AddRefs(serviceWorker));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
@ -3690,11 +3723,17 @@ ServiceWorkerManager::DispatchFetchEvent(const OriginAttributes& aOriginAttribut
|
||||
return;
|
||||
}
|
||||
|
||||
// if the ServiceWorker script fails to load for some reason, just resume
|
||||
// the original channel.
|
||||
nsCOMPtr<nsIRunnable> failRunnable =
|
||||
NS_NewRunnableMethod(aChannel, &nsIInterceptedChannel::ResetInterception);
|
||||
|
||||
nsAutoPtr<ServiceWorkerClientInfo> clientInfo;
|
||||
|
||||
if (!isNavigation) {
|
||||
MOZ_ASSERT(aDoc);
|
||||
aRv = GetDocumentController(aDoc->GetInnerWindow(), getter_AddRefs(serviceWorker));
|
||||
aRv = GetDocumentController(aDoc->GetInnerWindow(), failRunnable,
|
||||
getter_AddRefs(serviceWorker));
|
||||
clientInfo = new ServiceWorkerClientInfo(aDoc, aDoc->GetWindow());
|
||||
} else {
|
||||
nsCOMPtr<nsIChannel> internalChannel;
|
||||
@ -3723,6 +3762,7 @@ ServiceWorkerManager::DispatchFetchEvent(const OriginAttributes& aOriginAttribut
|
||||
nsRefPtr<ServiceWorker> sw;
|
||||
aRv = CreateServiceWorker(registration->mPrincipal,
|
||||
registration->mActiveWorker,
|
||||
failRunnable,
|
||||
getter_AddRefs(sw));
|
||||
serviceWorker = sw.forget();
|
||||
}
|
||||
@ -3806,7 +3846,9 @@ ServiceWorkerManager::GetDocumentRegistration(nsIDocument* aDoc,
|
||||
* the document was loaded.
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerManager::GetDocumentController(nsIDOMWindow* aWindow, nsISupports** aServiceWorker)
|
||||
ServiceWorkerManager::GetDocumentController(nsIDOMWindow* aWindow,
|
||||
nsIRunnable* aLoadFailedRunnable,
|
||||
nsISupports** aServiceWorker)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
|
||||
MOZ_ASSERT(window);
|
||||
@ -3825,6 +3867,7 @@ ServiceWorkerManager::GetDocumentController(nsIDOMWindow* aWindow, nsISupports**
|
||||
nsRefPtr<ServiceWorker> serviceWorker;
|
||||
rv = CreateServiceWorkerForWindow(window,
|
||||
registration->mActiveWorker,
|
||||
aLoadFailedRunnable,
|
||||
getter_AddRefs(serviceWorker));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
@ -3867,6 +3910,7 @@ ServiceWorkerManager::GetActive(nsIDOMWindow* aWindow,
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerManager::CreateServiceWorker(nsIPrincipal* aPrincipal,
|
||||
ServiceWorkerInfo* aInfo,
|
||||
nsIRunnable* aLoadFailedRunnable,
|
||||
ServiceWorker** aServiceWorker)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
@ -3921,6 +3965,8 @@ ServiceWorkerManager::CreateServiceWorker(nsIPrincipal* aPrincipal,
|
||||
// them here.
|
||||
WorkerPrivate::OverrideLoadInfoLoadGroup(info);
|
||||
|
||||
info.mLoadFailedAsyncRunnable = aLoadFailedRunnable;
|
||||
|
||||
RuntimeService* rs = RuntimeService::GetOrCreateService();
|
||||
if (!rs) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -420,11 +420,13 @@ private:
|
||||
NS_IMETHOD
|
||||
CreateServiceWorkerForWindow(nsPIDOMWindow* aWindow,
|
||||
ServiceWorkerInfo* aInfo,
|
||||
nsIRunnable* aLoadFailedRunnable,
|
||||
ServiceWorker** aServiceWorker);
|
||||
|
||||
NS_IMETHOD
|
||||
CreateServiceWorker(nsIPrincipal* aPrincipal,
|
||||
ServiceWorkerInfo* aInfo,
|
||||
nsIRunnable* aLoadFailedRunnable,
|
||||
ServiceWorker** aServiceWorker);
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -435,7 +437,8 @@ private:
|
||||
|
||||
already_AddRefed<ServiceWorker>
|
||||
CreateServiceWorkerForScope(const OriginAttributes& aOriginAttributes,
|
||||
const nsACString& aScope);
|
||||
const nsACString& aScope,
|
||||
nsIRunnable* aLoadFailedRunnable);
|
||||
|
||||
void
|
||||
InvalidateServiceWorkerRegistrationWorker(ServiceWorkerRegistrationInfo* aRegistration,
|
||||
|
@ -2384,6 +2384,9 @@ WorkerLoadInfo::StealFrom(WorkerLoadInfo& aOther)
|
||||
MOZ_ASSERT(!mLoadGroup);
|
||||
aOther.mLoadGroup.swap(mLoadGroup);
|
||||
|
||||
MOZ_ASSERT(!mLoadFailedAsyncRunnable);
|
||||
aOther.mLoadFailedAsyncRunnable.swap(mLoadFailedAsyncRunnable);
|
||||
|
||||
MOZ_ASSERT(!mInterfaceRequestor);
|
||||
aOther.mInterfaceRequestor.swap(mInterfaceRequestor);
|
||||
|
||||
@ -3418,7 +3421,7 @@ WorkerPrivateParent<Derived>::ForgetMainThreadObjects(
|
||||
AssertIsOnParentThread();
|
||||
MOZ_ASSERT(!mMainThreadObjectsForgotten);
|
||||
|
||||
static const uint32_t kDoomedCount = 9;
|
||||
static const uint32_t kDoomedCount = 10;
|
||||
|
||||
aDoomed.SetCapacity(kDoomedCount);
|
||||
|
||||
@ -3430,6 +3433,7 @@ WorkerPrivateParent<Derived>::ForgetMainThreadObjects(
|
||||
SwapToISupportsArray(mLoadInfo.mChannel, aDoomed);
|
||||
SwapToISupportsArray(mLoadInfo.mCSP, aDoomed);
|
||||
SwapToISupportsArray(mLoadInfo.mLoadGroup, aDoomed);
|
||||
SwapToISupportsArray(mLoadInfo.mLoadFailedAsyncRunnable, aDoomed);
|
||||
SwapToISupportsArray(mLoadInfo.mInterfaceRequestor, aDoomed);
|
||||
// Before adding anything here update kDoomedCount above!
|
||||
|
||||
@ -5466,6 +5470,19 @@ WorkerPrivate::RunBeforeNextEvent(nsIRunnable* aRunnable)
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
WorkerPrivate::MaybeDispatchLoadFailedRunnable()
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable = StealLoadFailedAsyncRunnable();
|
||||
if (!runnable) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable.forget())));
|
||||
}
|
||||
|
||||
void
|
||||
WorkerPrivate::InitializeGCTimers()
|
||||
{
|
||||
|
@ -798,6 +798,12 @@ public:
|
||||
void
|
||||
UpdateOverridenLoadGroup(nsILoadGroup* aBaseLoadGroup);
|
||||
|
||||
already_AddRefed<nsIRunnable>
|
||||
StealLoadFailedAsyncRunnable()
|
||||
{
|
||||
return mLoadInfo.mLoadFailedAsyncRunnable.forget();
|
||||
}
|
||||
|
||||
IMPL_EVENT_HANDLER(message)
|
||||
IMPL_EVENT_HANDLER(error)
|
||||
|
||||
@ -956,6 +962,9 @@ class WorkerPrivate : public WorkerPrivateParent<WorkerPrivate>
|
||||
|
||||
nsRefPtrHashtable<nsUint64HashKey, MessagePort> mWorkerPorts;
|
||||
|
||||
// fired on the main thread if the worker script fails to load
|
||||
nsCOMPtr<nsIRunnable> mLoadFailedRunnable;
|
||||
|
||||
TimeStamp mKillTime;
|
||||
uint32_t mErrorHandlerRecursionCount;
|
||||
uint32_t mNextTimeoutId;
|
||||
@ -1367,6 +1376,9 @@ public:
|
||||
bool
|
||||
RunBeforeNextEvent(nsIRunnable* aRunnable);
|
||||
|
||||
void
|
||||
MaybeDispatchLoadFailedRunnable();
|
||||
|
||||
private:
|
||||
WorkerPrivate(JSContext* aCx, WorkerPrivate* aParent,
|
||||
const nsAString& aScriptURL, bool aIsChromeWorker,
|
||||
|
@ -39,6 +39,7 @@ class nsIPrincipal;
|
||||
class nsILoadGroup;
|
||||
class nsITabChild;
|
||||
class nsIChannel;
|
||||
class nsIRunnable;
|
||||
class nsIURI;
|
||||
|
||||
namespace mozilla {
|
||||
@ -221,6 +222,12 @@ struct WorkerLoadInfo
|
||||
nsCOMPtr<nsIChannel> mChannel;
|
||||
nsCOMPtr<nsILoadGroup> mLoadGroup;
|
||||
|
||||
// mLoadFailedAsyncRunnable will execute on main thread if script loading
|
||||
// fails during script loading. If script loading is never started due to
|
||||
// a synchronous error, then the runnable is never executed. The runnable
|
||||
// is guaranteed to be released on the main thread.
|
||||
nsCOMPtr<nsIRunnable> mLoadFailedAsyncRunnable;
|
||||
|
||||
class InterfaceRequestor final : public nsIInterfaceRequestor
|
||||
{
|
||||
NS_DECL_ISUPPORTS
|
||||
|
Loading…
x
Reference in New Issue
Block a user