mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Bug 984050 - Persist ServiceWorkerRegistrations. r=bent, r=nsm
This commit is contained in:
parent
2d47b873af
commit
78ecfc7b0d
@ -6,6 +6,7 @@
|
||||
#include "domstubs.idl"
|
||||
|
||||
interface nsIDocument;
|
||||
interface nsIPrincipal;
|
||||
interface nsIURI;
|
||||
|
||||
[builtinclass, uuid(d4367ffe-e435-4195-95f8-0a51b1bbfdfb)]
|
||||
@ -17,7 +18,7 @@ interface nsIServiceWorkerUnregisterCallback : nsISupports
|
||||
[noscript] void UnregisterFailed();
|
||||
};
|
||||
|
||||
[builtinclass, uuid(430f02bf-63d0-44ab-9a59-7bd49c608949)]
|
||||
[builtinclass, uuid(861b55e9-d6ac-47cf-a528-8590e9b44de6)]
|
||||
interface nsIServiceWorkerManager : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -34,7 +35,8 @@ interface nsIServiceWorkerManager : nsISupports
|
||||
* Unregister an existing ServiceWorker registration for `aScope`.
|
||||
* It keeps aCallback alive until the operation is concluded.
|
||||
*/
|
||||
void unregister(in nsIServiceWorkerUnregisterCallback aCallback,
|
||||
void unregister(in nsIPrincipal aPrincipal,
|
||||
in nsIServiceWorkerUnregisterCallback aCallback,
|
||||
in DOMString aScope);
|
||||
|
||||
// Returns a Promise
|
||||
|
@ -19,6 +19,7 @@ include DOMTypes;
|
||||
include JavaScriptTypes;
|
||||
include URIParams;
|
||||
include PContentPermission;
|
||||
include ServiceWorkerRegistrarTypes;
|
||||
|
||||
|
||||
using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h";
|
||||
@ -65,6 +66,11 @@ struct NativeKeyBinding
|
||||
CommandInt[] richTextCommands;
|
||||
};
|
||||
|
||||
struct BrowserConfiguration
|
||||
{
|
||||
ServiceWorkerRegistrationData[] serviceWorkerRegistrations;
|
||||
};
|
||||
|
||||
union MaybeNativeKeyBinding
|
||||
{
|
||||
NativeKeyBinding;
|
||||
@ -471,7 +477,7 @@ child:
|
||||
nullable PRenderFrame renderFrame,
|
||||
bool parentIsActive);
|
||||
|
||||
LoadURL(nsCString uri);
|
||||
LoadURL(nsCString uri, BrowserConfiguration config);
|
||||
|
||||
CacheFileDescriptor(nsString path, FileDescriptor fd);
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/EventListenerManager.h"
|
||||
#include "mozilla/IntentionalCrash.h"
|
||||
#include "mozilla/dom/workers/ServiceWorkerManager.h"
|
||||
#include "mozilla/dom/indexedDB/PIndexedDBPermissionRequestChild.h"
|
||||
#include "mozilla/plugins/PluginWidgetChild.h"
|
||||
#include "mozilla/ipc/DocumentRendererChild.h"
|
||||
@ -99,6 +100,7 @@
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::dom::ipc;
|
||||
using namespace mozilla::dom::workers;
|
||||
using namespace mozilla::ipc;
|
||||
using namespace mozilla::layers;
|
||||
using namespace mozilla::layout;
|
||||
@ -1566,7 +1568,7 @@ TabChild::ProvideWindowCommon(nsIDOMWindow* aOpener,
|
||||
}
|
||||
|
||||
if (!urlToLoad.IsEmpty()) {
|
||||
newChild->RecvLoadURL(urlToLoad);
|
||||
newChild->RecvLoadURL(urlToLoad, BrowserConfiguration());
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMWindow> win = do_GetInterface(newChild->WebNavigation());
|
||||
@ -1717,11 +1719,12 @@ TabChild::IsRootContentDocument()
|
||||
}
|
||||
|
||||
bool
|
||||
TabChild::RecvLoadURL(const nsCString& uri)
|
||||
TabChild::RecvLoadURL(const nsCString& aURI,
|
||||
const BrowserConfiguration& aConfiguration)
|
||||
{
|
||||
SetProcessNameToAppName();
|
||||
|
||||
nsresult rv = WebNavigation()->LoadURI(NS_ConvertUTF8toUTF16(uri).get(),
|
||||
nsresult rv = WebNavigation()->LoadURI(NS_ConvertUTF8toUTF16(aURI).get(),
|
||||
nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP |
|
||||
nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_OWNER,
|
||||
nullptr, nullptr, nullptr);
|
||||
@ -1730,9 +1733,13 @@ TabChild::RecvLoadURL(const nsCString& uri)
|
||||
}
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("URL"), uri);
|
||||
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("URL"), aURI);
|
||||
#endif
|
||||
|
||||
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
|
||||
MOZ_ASSERT(swm);
|
||||
swm->LoadRegistrations(aConfiguration.serviceWorkerRegistrations());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -312,7 +312,8 @@ public:
|
||||
const ViewID& aViewId,
|
||||
const bool& aIsRoot,
|
||||
const ZoomConstraints& aConstraints) MOZ_OVERRIDE;
|
||||
virtual bool RecvLoadURL(const nsCString& uri) MOZ_OVERRIDE;
|
||||
virtual bool RecvLoadURL(const nsCString& aURI,
|
||||
const BrowserConfiguration& aConfiguration) MOZ_OVERRIDE;
|
||||
virtual bool RecvCacheFileDescriptor(const nsString& aPath,
|
||||
const FileDescriptor& aFileDescriptor)
|
||||
MOZ_OVERRIDE;
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "mozilla/BrowserElementParent.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/PContentPermissionRequestParent.h"
|
||||
#include "mozilla/dom/ServiceWorkerRegistrar.h"
|
||||
#include "mozilla/dom/indexedDB/ActorsParent.h"
|
||||
#include "mozilla/plugins/PluginWidgetParent.h"
|
||||
#include "mozilla/EventStateManager.h"
|
||||
@ -45,6 +46,7 @@
|
||||
#include "nsIDOMWindowUtils.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsILoadInfo.h"
|
||||
#include "nsPrincipal.h"
|
||||
#include "nsIPromptFactory.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIWebBrowserChrome.h"
|
||||
@ -693,6 +695,19 @@ TabParent::SendLoadRemoteScript(const nsString& aURL,
|
||||
return PBrowserParent::SendLoadRemoteScript(aURL, aRunInGlobalScope);
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::InitBrowserConfiguration(nsIURI* aURI,
|
||||
BrowserConfiguration& aConfiguration)
|
||||
{
|
||||
// Get the list of ServiceWorkerRegistation for this origin.
|
||||
nsRefPtr<ServiceWorkerRegistrar> swr = ServiceWorkerRegistrar::Get();
|
||||
MOZ_ASSERT(swr);
|
||||
|
||||
swr->GetRegistrations(aConfiguration.serviceWorkerRegistrations());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
TabParent::LoadURL(nsIURI* aURI)
|
||||
{
|
||||
@ -727,7 +742,13 @@ TabParent::LoadURL(nsIURI* aURI)
|
||||
}
|
||||
mSendOfflineStatus = false;
|
||||
|
||||
unused << SendLoadURL(spec);
|
||||
// This object contains the configuration for this new app.
|
||||
BrowserConfiguration configuration;
|
||||
if (NS_WARN_IF(!InitBrowserConfiguration(aURI, configuration))) {
|
||||
return;
|
||||
}
|
||||
|
||||
unused << SendLoadURL(spec, configuration);
|
||||
|
||||
// If this app is a packaged app then we can speed startup by sending over
|
||||
// the file descriptor for the "application.zip" file that it will
|
||||
|
@ -403,6 +403,9 @@ protected:
|
||||
|
||||
bool SendCompositionChangeEvent(mozilla::WidgetCompositionEvent& event);
|
||||
|
||||
bool InitBrowserConfiguration(nsIURI* aURI,
|
||||
BrowserConfiguration& aConfiguration);
|
||||
|
||||
// IME
|
||||
static TabParent *mIMETabParent;
|
||||
nsString mIMECacheText;
|
||||
|
@ -112,6 +112,7 @@ include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
LOCAL_INCLUDES += [
|
||||
'/caps',
|
||||
'/chrome',
|
||||
'/docshell/base',
|
||||
'/dom/base',
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "ServiceWorkerManager.h"
|
||||
|
||||
#include "nsIAppsService.h"
|
||||
#include "nsIDOMEventTarget.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
@ -21,6 +22,9 @@
|
||||
#include "mozilla/dom/InstallEventBinding.h"
|
||||
#include "mozilla/dom/Navigator.h"
|
||||
#include "mozilla/dom/PromiseNativeHandler.h"
|
||||
#include "mozilla/ipc/BackgroundChild.h"
|
||||
#include "mozilla/ipc/PBackgroundChild.h"
|
||||
#include "mozilla/ipc/PBackgroundSharedTypes.h"
|
||||
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
@ -45,9 +49,58 @@
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
struct ServiceWorkerManager::PendingOperation
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> mRunnable;
|
||||
|
||||
ServiceWorkerJobQueue* mQueue;
|
||||
nsRefPtr<ServiceWorkerJob> mJob;
|
||||
|
||||
ServiceWorkerRegistrationData mRegistration;
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
nsresult
|
||||
PopulateRegistrationData(nsIPrincipal* aPrincipal,
|
||||
const ServiceWorkerRegistrationInfo* aRegistration,
|
||||
ServiceWorkerRegistrationData& aData)
|
||||
{
|
||||
MOZ_ASSERT(aPrincipal);
|
||||
MOZ_ASSERT(aRegistration);
|
||||
|
||||
bool isNullPrincipal = true;
|
||||
nsresult rv = aPrincipal->GetIsNullPrincipal(&isNullPrincipal);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// No null principals.
|
||||
if (NS_WARN_IF(isNullPrincipal)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
rv = PrincipalToPrincipalInfo(aPrincipal, &aData.principal());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
aData.scope() = aRegistration->mScope;
|
||||
aData.scriptSpec() = aRegistration->mScriptSpec;
|
||||
|
||||
if (aRegistration->mActiveWorker) {
|
||||
aData.currentWorkerURL() = aRegistration->mActiveWorker->ScriptSpec();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
NS_IMPL_ISUPPORTS0(ServiceWorkerJob)
|
||||
NS_IMPL_ISUPPORTS0(ServiceWorkerRegistrationInfo)
|
||||
|
||||
@ -93,10 +146,12 @@ ServiceWorkerRegistrationInfo::Clear()
|
||||
WhichServiceWorker::ACTIVE_WORKER);
|
||||
}
|
||||
|
||||
ServiceWorkerRegistrationInfo::ServiceWorkerRegistrationInfo(const nsACString& aScope)
|
||||
: mControlledDocumentsCounter(0),
|
||||
mScope(aScope),
|
||||
mPendingUninstall(false)
|
||||
ServiceWorkerRegistrationInfo::ServiceWorkerRegistrationInfo(const nsACString& aScope,
|
||||
nsIPrincipal* aPrincipal)
|
||||
: mControlledDocumentsCounter(0)
|
||||
, mScope(aScope)
|
||||
, mPrincipal(aPrincipal)
|
||||
, mPendingUninstall(false)
|
||||
{ }
|
||||
|
||||
ServiceWorkerRegistrationInfo::~ServiceWorkerRegistrationInfo()
|
||||
@ -115,6 +170,7 @@ NS_IMPL_RELEASE(ServiceWorkerManager)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(ServiceWorkerManager)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIServiceWorkerManager)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIIPCBackgroundChildCreateCallback)
|
||||
if (aIID.Equals(NS_GET_IID(ServiceWorkerManager)))
|
||||
foundInterface = static_cast<nsIServiceWorkerManager*>(this);
|
||||
else
|
||||
@ -122,7 +178,19 @@ NS_INTERFACE_MAP_BEGIN(ServiceWorkerManager)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
ServiceWorkerManager::ServiceWorkerManager()
|
||||
: mActor(nullptr)
|
||||
{
|
||||
// Register this component to PBackground.
|
||||
MOZ_ALWAYS_TRUE(BackgroundChild::GetOrCreateForCurrentThread(this));
|
||||
|
||||
if (XRE_GetProcessType() == GeckoProcessType_Default) {
|
||||
nsRefPtr<ServiceWorkerRegistrar> swr = ServiceWorkerRegistrar::Get();
|
||||
MOZ_ASSERT(swr);
|
||||
|
||||
nsTArray<ServiceWorkerRegistrationData> data;
|
||||
swr->GetRegistrations(data);
|
||||
LoadRegistrations(data);
|
||||
}
|
||||
}
|
||||
|
||||
ServiceWorkerManager::~ServiceWorkerManager()
|
||||
@ -380,6 +448,7 @@ class ServiceWorkerRegisterJob MOZ_FINAL : public ServiceWorkerJob,
|
||||
nsCString mScriptSpec;
|
||||
nsRefPtr<ServiceWorkerRegistrationInfo> mRegistration;
|
||||
nsRefPtr<ServiceWorkerUpdateFinishCallback> mCallback;
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
|
||||
~ServiceWorkerRegisterJob()
|
||||
{ }
|
||||
@ -397,11 +466,13 @@ public:
|
||||
ServiceWorkerRegisterJob(ServiceWorkerJobQueue* aQueue,
|
||||
const nsCString& aScope,
|
||||
const nsCString& aScriptSpec,
|
||||
ServiceWorkerUpdateFinishCallback* aCallback)
|
||||
ServiceWorkerUpdateFinishCallback* aCallback,
|
||||
nsIPrincipal* aPrincipal)
|
||||
: ServiceWorkerJob(aQueue)
|
||||
, mScope(aScope)
|
||||
, mScriptSpec(aScriptSpec)
|
||||
, mCallback(aCallback)
|
||||
, mPrincipal(aPrincipal)
|
||||
, mJobType(REGISTER_JOB)
|
||||
{ }
|
||||
|
||||
@ -418,8 +489,17 @@ public:
|
||||
void
|
||||
Start() MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
|
||||
if (!swm->HasBackgroundActor()) {
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
NS_NewRunnableMethod(this, &ServiceWorkerRegisterJob::Start);
|
||||
swm->AppendPendingOperation(runnable);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mJobType == REGISTER_JOB) {
|
||||
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
|
||||
mRegistration = swm->GetRegistration(mScope);
|
||||
|
||||
if (mRegistration) {
|
||||
@ -432,10 +512,11 @@ public:
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
mRegistration = swm->CreateNewRegistration(mScope);
|
||||
mRegistration = swm->CreateNewRegistration(mScope, mPrincipal);
|
||||
}
|
||||
|
||||
mRegistration->mScriptSpec = mScriptSpec;
|
||||
swm->StoreRegistration(mPrincipal, mRegistration);
|
||||
} else {
|
||||
MOZ_ASSERT(mJobType == UPDATE_JOB);
|
||||
}
|
||||
@ -866,13 +947,36 @@ ServiceWorkerManager::Register(nsIDOMWindow* aWindow,
|
||||
new ServiceWorkerResolveWindowPromiseOnUpdateCallback(window, promise);
|
||||
|
||||
nsRefPtr<ServiceWorkerRegisterJob> job =
|
||||
new ServiceWorkerRegisterJob(queue, cleanedScope, spec, cb);
|
||||
new ServiceWorkerRegisterJob(queue, cleanedScope, spec, cb, documentPrincipal);
|
||||
queue->Append(job);
|
||||
|
||||
promise.forget(aPromise);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerManager::AppendPendingOperation(ServiceWorkerJobQueue* aQueue,
|
||||
ServiceWorkerJob* aJob)
|
||||
{
|
||||
MOZ_ASSERT(!mActor);
|
||||
MOZ_ASSERT(aQueue);
|
||||
MOZ_ASSERT(aJob);
|
||||
|
||||
PendingOperation* opt = mPendingOperations.AppendElement();
|
||||
opt->mQueue = aQueue;
|
||||
opt->mJob = aJob;
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerManager::AppendPendingOperation(nsIRunnable* aRunnable)
|
||||
{
|
||||
MOZ_ASSERT(!mActor);
|
||||
MOZ_ASSERT(aRunnable);
|
||||
|
||||
PendingOperation* opt = mPendingOperations.AppendElement();
|
||||
opt->mRunnable = aRunnable;
|
||||
}
|
||||
|
||||
/*
|
||||
* Used to handle ExtendableEvent::waitUntil() and proceed with
|
||||
* installation/activation.
|
||||
@ -1027,6 +1131,7 @@ ServiceWorkerRegistrationInfo::Activate()
|
||||
mActiveWorker->UpdateState(ServiceWorkerState::Activating);
|
||||
|
||||
swm->CheckPendingReadyPromises();
|
||||
swm->StoreRegistration(mPrincipal, this);
|
||||
|
||||
// "Queue a task to fire a simple event named controllerchange..."
|
||||
nsCOMPtr<nsIRunnable> controllerChangeRunnable =
|
||||
@ -1382,6 +1487,7 @@ class ServiceWorkerUnregisterJob MOZ_FINAL : public ServiceWorkerJob
|
||||
nsRefPtr<ServiceWorkerRegistrationInfo> mRegistration;
|
||||
const nsCString mScope;
|
||||
nsCOMPtr<nsIServiceWorkerUnregisterCallback> mCallback;
|
||||
PrincipalInfo mPrincipalInfo;
|
||||
|
||||
~ServiceWorkerUnregisterJob()
|
||||
{ }
|
||||
@ -1389,10 +1495,12 @@ class ServiceWorkerUnregisterJob MOZ_FINAL : public ServiceWorkerJob
|
||||
public:
|
||||
ServiceWorkerUnregisterJob(ServiceWorkerJobQueue* aQueue,
|
||||
const nsACString& aScope,
|
||||
nsIServiceWorkerUnregisterCallback* aCallback)
|
||||
nsIServiceWorkerUnregisterCallback* aCallback,
|
||||
PrincipalInfo& aPrincipalInfo)
|
||||
: ServiceWorkerJob(aQueue)
|
||||
, mScope(aScope)
|
||||
, mCallback(aCallback)
|
||||
, mPrincipalInfo(aPrincipalInfo)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
}
|
||||
@ -1445,6 +1553,9 @@ private:
|
||||
swm->RemoveRegistration(registration);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(swm->mActor);
|
||||
swm->mActor->SendUnregisterServiceWorker(mPrincipalInfo,
|
||||
NS_ConvertUTF8toUTF16(mScope));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1457,10 +1568,12 @@ private:
|
||||
};
|
||||
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerManager::Unregister(nsIServiceWorkerUnregisterCallback* aCallback,
|
||||
ServiceWorkerManager::Unregister(nsIPrincipal* aPrincipal,
|
||||
nsIServiceWorkerUnregisterCallback* aCallback,
|
||||
const nsAString& aScope)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aPrincipal);
|
||||
MOZ_ASSERT(aCallback);
|
||||
|
||||
// This is not accessible by content, and callers should always ensure scope is
|
||||
@ -1477,9 +1590,21 @@ ServiceWorkerManager::Unregister(nsIServiceWorkerUnregisterCallback* aCallback,
|
||||
ServiceWorkerJobQueue* queue = GetOrCreateJobQueue(scope);
|
||||
MOZ_ASSERT(queue);
|
||||
|
||||
PrincipalInfo principalInfo;
|
||||
if (NS_WARN_IF(NS_FAILED(PrincipalToPrincipalInfo(aPrincipal,
|
||||
&principalInfo)))) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
nsRefPtr<ServiceWorkerUnregisterJob> job =
|
||||
new ServiceWorkerUnregisterJob(queue, scope, aCallback);
|
||||
queue->Append(job);
|
||||
new ServiceWorkerUnregisterJob(queue, scope, aCallback, principalInfo);
|
||||
|
||||
if (mActor) {
|
||||
queue->Append(job);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
AppendPendingOperation(queue, job);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1613,6 +1738,85 @@ ServiceWorkerManager::CreateServiceWorkerForWindow(nsPIDOMWindow* aWindow,
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerManager::LoadRegistrations(
|
||||
const nsTArray<ServiceWorkerRegistrationData>& aRegistrations)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
for (uint32_t i = 0, len = aRegistrations.Length(); i < len; ++i) {
|
||||
nsCOMPtr<nsIPrincipal> principal =
|
||||
PrincipalInfoToPrincipal(aRegistrations[i].principal());
|
||||
if (!principal) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ServiceWorkerRegistrationInfo* registration =
|
||||
CreateNewRegistration(aRegistrations[i].scope(), principal);
|
||||
|
||||
registration->mScriptSpec = aRegistrations[i].scriptSpec();
|
||||
|
||||
registration->mActiveWorker =
|
||||
new ServiceWorkerInfo(registration, aRegistrations[i].currentWorkerURL());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerManager::ActorFailed()
|
||||
{
|
||||
MOZ_CRASH("Failed to create a PBackgroundChild actor!");
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerManager::ActorCreated(mozilla::ipc::PBackgroundChild* aActor)
|
||||
{
|
||||
MOZ_ASSERT(aActor);
|
||||
MOZ_ASSERT(!mActor);
|
||||
mActor = aActor;
|
||||
|
||||
// Flush the pending requests.
|
||||
for (uint32_t i = 0, len = mPendingOperations.Length(); i < len; ++i) {
|
||||
MOZ_ASSERT(mPendingOperations[i].mRunnable ||
|
||||
(mPendingOperations[i].mJob && mPendingOperations[i].mQueue));
|
||||
|
||||
if (mPendingOperations[i].mRunnable) {
|
||||
nsresult rv = NS_DispatchToCurrentThread(mPendingOperations[i].mRunnable);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to dispatch a runnable.");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
mPendingOperations[i].mQueue->Append(mPendingOperations[i].mJob);
|
||||
}
|
||||
}
|
||||
|
||||
mPendingOperations.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerManager::StoreRegistration(
|
||||
nsIPrincipal* aPrincipal,
|
||||
ServiceWorkerRegistrationInfo* aRegistration)
|
||||
{
|
||||
MOZ_ASSERT(mActor);
|
||||
MOZ_ASSERT(aPrincipal);
|
||||
MOZ_ASSERT(aRegistration);
|
||||
|
||||
ServiceWorkerRegistrationData data;
|
||||
nsresult rv = PopulateRegistrationData(aPrincipal, aRegistration, data);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
PrincipalInfo principalInfo;
|
||||
if (NS_WARN_IF(NS_FAILED(PrincipalToPrincipalInfo(aPrincipal,
|
||||
&principalInfo)))) {
|
||||
return;
|
||||
}
|
||||
|
||||
mActor->SendRegisterServiceWorker(data);
|
||||
}
|
||||
|
||||
already_AddRefed<ServiceWorkerRegistrationInfo>
|
||||
ServiceWorkerManager::GetServiceWorkerRegistrationInfo(nsPIDOMWindow* aWindow)
|
||||
{
|
||||
@ -2166,7 +2370,8 @@ ServiceWorkerManager::FireControllerChange(ServiceWorkerRegistrationInfo* aRegis
|
||||
}
|
||||
|
||||
ServiceWorkerRegistrationInfo*
|
||||
ServiceWorkerManager::CreateNewRegistration(const nsCString& aScope)
|
||||
ServiceWorkerManager::CreateNewRegistration(const nsCString& aScope,
|
||||
nsIPrincipal* aPrincipal)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
AssertIsOnMainThread();
|
||||
@ -2174,7 +2379,7 @@ ServiceWorkerManager::CreateNewRegistration(const nsCString& aScope)
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(scopeURI), aScope, nullptr, nullptr);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
#endif
|
||||
ServiceWorkerRegistrationInfo* registration = new ServiceWorkerRegistrationInfo(aScope);
|
||||
ServiceWorkerRegistrationInfo* registration = new ServiceWorkerRegistrationInfo(aScope, aPrincipal);
|
||||
// From now on ownership of registration is with
|
||||
// mServiceWorkerRegistrationInfos.
|
||||
mServiceWorkerRegistrationInfos.Put(aScope, registration);
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "nsIServiceWorkerManager.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#include "ipc/IPCMessageUtils.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
@ -17,6 +18,10 @@
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/ServiceWorkerBinding.h" // For ServiceWorkerState
|
||||
#include "mozilla/dom/ServiceWorkerCommon.h"
|
||||
#include "mozilla/dom/ServiceWorkerRegistrar.h"
|
||||
#include "mozilla/dom/ServiceWorkerRegistrarTypes.h"
|
||||
#include "mozilla/ipc/BackgroundUtils.h"
|
||||
#include "nsIIPCBackgroundChildCreateCallback.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
@ -26,6 +31,11 @@
|
||||
class nsIScriptError;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace ipc {
|
||||
class BackgroundChild;
|
||||
}
|
||||
|
||||
namespace dom {
|
||||
|
||||
class ServiceWorkerRegistration;
|
||||
@ -131,6 +141,8 @@ public:
|
||||
// the URLs of the following three workers.
|
||||
nsCString mScriptSpec;
|
||||
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
|
||||
nsRefPtr<ServiceWorkerInfo> mActiveWorker;
|
||||
nsRefPtr<ServiceWorkerInfo> mWaitingWorker;
|
||||
nsRefPtr<ServiceWorkerInfo> mInstallingWorker;
|
||||
@ -141,7 +153,8 @@ public:
|
||||
bool mPendingUninstall;
|
||||
bool mWaitingToActivate;
|
||||
|
||||
explicit ServiceWorkerRegistrationInfo(const nsACString& aScope);
|
||||
explicit ServiceWorkerRegistrationInfo(const nsACString& aScope,
|
||||
nsIPrincipal* aPrincipal);
|
||||
|
||||
already_AddRefed<ServiceWorkerInfo>
|
||||
Newest()
|
||||
@ -218,6 +231,12 @@ public:
|
||||
return mScriptSpec;
|
||||
}
|
||||
|
||||
void SetScriptSpec(const nsCString& aSpec)
|
||||
{
|
||||
MOZ_ASSERT(!aSpec.IsEmpty());
|
||||
mScriptSpec = aSpec;
|
||||
}
|
||||
|
||||
explicit ServiceWorkerInfo(ServiceWorkerRegistrationInfo* aReg,
|
||||
const nsACString& aScriptSpec)
|
||||
: mRegistration(aReg)
|
||||
@ -266,7 +285,9 @@ public:
|
||||
* installation, querying and event dispatch of ServiceWorkers for all the
|
||||
* origins in the process.
|
||||
*/
|
||||
class ServiceWorkerManager MOZ_FINAL : public nsIServiceWorkerManager
|
||||
class ServiceWorkerManager MOZ_FINAL
|
||||
: public nsIServiceWorkerManager
|
||||
, public nsIIPCBackgroundChildCreateCallback
|
||||
{
|
||||
friend class ActivationRunnable;
|
||||
friend class ServiceWorkerRegistrationInfo;
|
||||
@ -280,14 +301,12 @@ class ServiceWorkerManager MOZ_FINAL : public nsIServiceWorkerManager
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISERVICEWORKERMANAGER
|
||||
NS_DECL_NSIIPCBACKGROUNDCHILDCREATECALLBACK
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_SERVICEWORKERMANAGER_IMPL_IID)
|
||||
|
||||
static ServiceWorkerManager* FactoryCreate()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
if (!Preferences::GetBool("dom.serviceWorkers.enabled")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ServiceWorkerManager* res = new ServiceWorkerManager;
|
||||
NS_ADDREF(res);
|
||||
@ -325,7 +344,7 @@ public:
|
||||
}
|
||||
|
||||
ServiceWorkerRegistrationInfo*
|
||||
CreateNewRegistration(const nsCString& aScope);
|
||||
CreateNewRegistration(const nsCString& aScope, nsIPrincipal* aPrincipal);
|
||||
|
||||
void
|
||||
RemoveRegistration(ServiceWorkerRegistrationInfo* aRegistration)
|
||||
@ -341,6 +360,9 @@ public:
|
||||
return mJobQueues.LookupOrAdd(aScope);
|
||||
}
|
||||
|
||||
void StoreRegistration(nsIPrincipal* aPrincipal,
|
||||
ServiceWorkerRegistrationInfo* aRegistration);
|
||||
|
||||
void
|
||||
FinishFetch(ServiceWorkerRegistrationInfo* aRegistration);
|
||||
|
||||
@ -364,6 +386,9 @@ public:
|
||||
static already_AddRefed<ServiceWorkerManager>
|
||||
GetInstance();
|
||||
|
||||
void LoadRegistrations(
|
||||
const nsTArray<ServiceWorkerRegistrationData>& aRegistrations);
|
||||
|
||||
private:
|
||||
ServiceWorkerManager();
|
||||
~ServiceWorkerManager();
|
||||
@ -450,12 +475,26 @@ private:
|
||||
nsRefPtr<Promise> mPromise;
|
||||
};
|
||||
|
||||
void AppendPendingOperation(nsIRunnable* aRunnable);
|
||||
void AppendPendingOperation(ServiceWorkerJobQueue* aQueue,
|
||||
ServiceWorkerJob* aJob);
|
||||
|
||||
bool HasBackgroundActor() const
|
||||
{
|
||||
return !!mActor;
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
CheckPendingReadyPromisesEnumerator(nsISupports* aSupports,
|
||||
nsAutoPtr<PendingReadyPromise>& aData,
|
||||
void* aUnused);
|
||||
|
||||
nsClassHashtable<nsISupportsHashKey, PendingReadyPromise> mPendingReadyPromises;
|
||||
|
||||
mozilla::ipc::PBackgroundChild* mActor;
|
||||
|
||||
struct PendingOperation;
|
||||
nsTArray<PendingOperation> mPendingOperations;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(ServiceWorkerManager,
|
||||
|
671
dom/workers/ServiceWorkerRegistrar.cpp
Normal file
671
dom/workers/ServiceWorkerRegistrar.cpp
Normal file
@ -0,0 +1,671 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ServiceWorkerRegistrar.h"
|
||||
#include "mozilla/dom/ServiceWorkerRegistrarTypes.h"
|
||||
|
||||
#include "nsIEventTarget.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsILineInputStream.h"
|
||||
#include "nsIObserverService.h"
|
||||
|
||||
#include "MainThreadUtils.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/ipc/BackgroundChild.h"
|
||||
#include "mozilla/ipc/BackgroundParent.h"
|
||||
#include "mozilla/ipc/PBackgroundChild.h"
|
||||
#include "mozilla/ModuleUtils.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "nsAppDirectoryServiceDefs.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsDirectoryServiceUtils.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
namespace {
|
||||
|
||||
StaticRefPtr<ServiceWorkerRegistrar> gServiceWorkerRegistrar;
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
NS_IMPL_ISUPPORTS(ServiceWorkerRegistrar,
|
||||
nsIObserver)
|
||||
|
||||
void
|
||||
ServiceWorkerRegistrar::Initialize()
|
||||
{
|
||||
MOZ_ASSERT(!gServiceWorkerRegistrar);
|
||||
|
||||
if (XRE_GetProcessType() != GeckoProcessType_Default) {
|
||||
return;
|
||||
}
|
||||
|
||||
gServiceWorkerRegistrar = new ServiceWorkerRegistrar();
|
||||
ClearOnShutdown(&gServiceWorkerRegistrar);
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (obs) {
|
||||
DebugOnly<nsresult> rv = obs->AddObserver(gServiceWorkerRegistrar,
|
||||
"profile-after-change", false);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
|
||||
rv = obs->AddObserver(gServiceWorkerRegistrar, "profile-before-change",
|
||||
false);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<ServiceWorkerRegistrar>
|
||||
ServiceWorkerRegistrar::Get()
|
||||
{
|
||||
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
||||
|
||||
MOZ_ASSERT(gServiceWorkerRegistrar);
|
||||
nsRefPtr<ServiceWorkerRegistrar> service = gServiceWorkerRegistrar.get();
|
||||
return service.forget();
|
||||
}
|
||||
|
||||
ServiceWorkerRegistrar::ServiceWorkerRegistrar()
|
||||
: mMonitor("ServiceWorkerRegistrar.mMonitor")
|
||||
, mDataLoaded(false)
|
||||
, mShuttingDown(false)
|
||||
, mShutdownCompleteFlag(nullptr)
|
||||
, mRunnableCounter(0)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
||||
ServiceWorkerRegistrar::~ServiceWorkerRegistrar()
|
||||
{
|
||||
MOZ_ASSERT(!mRunnableCounter);
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerRegistrar::GetRegistrations(
|
||||
nsTArray<ServiceWorkerRegistrationData>& aValues)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aValues.IsEmpty());
|
||||
|
||||
// If we don't have the profile directory, profile is not started yet (and
|
||||
// probably we are in a utest).
|
||||
if (!mProfileDir) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We care just about the first execution because this can be blocked by
|
||||
// loading data from disk.
|
||||
static bool firstTime = true;
|
||||
TimeStamp startTime;
|
||||
|
||||
if (firstTime) {
|
||||
startTime = TimeStamp::NowLoRes();
|
||||
}
|
||||
|
||||
{
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
|
||||
// Waiting for data loaded.
|
||||
mMonitor.AssertCurrentThreadOwns();
|
||||
while (!mDataLoaded) {
|
||||
mMonitor.Wait();
|
||||
}
|
||||
|
||||
aValues.AppendElements(mData);
|
||||
}
|
||||
|
||||
if (firstTime) {
|
||||
firstTime = false;
|
||||
Telemetry::AccumulateTimeDelta(
|
||||
Telemetry::SERVICE_WORKER_REGISTRATION_LOADING,
|
||||
startTime);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerRegistrar::RegisterServiceWorker(
|
||||
const ServiceWorkerRegistrationData& aData)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
if (mShuttingDown) {
|
||||
NS_WARNING("Failed to register a serviceWorker during shutting down.");
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
MOZ_ASSERT(mDataLoaded);
|
||||
|
||||
bool found = false;
|
||||
for (uint32_t i = 0, len = mData.Length(); i < len; ++i) {
|
||||
if (mData[i].scope() == aData.scope()) {
|
||||
mData[i] = aData;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
mData.AppendElement(aData);
|
||||
}
|
||||
}
|
||||
|
||||
ScheduleSaveData();
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerRegistrar::UnregisterServiceWorker(const nsACString& aScope)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
if (mShuttingDown) {
|
||||
NS_WARNING("Failed to unregister a serviceWorker during shutting down.");
|
||||
return;
|
||||
}
|
||||
|
||||
bool deleted = false;
|
||||
|
||||
{
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
MOZ_ASSERT(mDataLoaded);
|
||||
|
||||
for (uint32_t i = 0; i < mData.Length(); ++i) {
|
||||
if (mData[i].scope() == aScope) {
|
||||
mData.RemoveElementAt(i);
|
||||
deleted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (deleted) {
|
||||
ScheduleSaveData();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerRegistrar::LoadData()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(!mDataLoaded);
|
||||
|
||||
nsresult rv = ReadData();
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
DeleteData();
|
||||
// Also if the reading failed we have to notify what is waiting for data.
|
||||
}
|
||||
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
MOZ_ASSERT(!mDataLoaded);
|
||||
mDataLoaded = true;
|
||||
mMonitor.Notify();
|
||||
}
|
||||
|
||||
nsresult
|
||||
ServiceWorkerRegistrar::ReadData()
|
||||
{
|
||||
// We cannot assert about the correct thread because normally this method
|
||||
// runs on a IO thread, but in gTests we call it from the main-thread.
|
||||
|
||||
MOZ_ASSERT(mProfileDir);
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
nsresult rv = mProfileDir->Clone(getter_AddRefs(file));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = file->Append(NS_LITERAL_STRING(SERVICEWORKERREGISTRAR_FILE));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool exists;
|
||||
rv = file->Exists(&exists);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!exists) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
rv = NS_NewLocalFileInputStream(getter_AddRefs(stream), file);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsILineInputStream> lineInputStream = do_QueryInterface(stream);
|
||||
MOZ_ASSERT(lineInputStream);
|
||||
|
||||
nsAutoCString line;
|
||||
bool hasMoreLines;
|
||||
rv = lineInputStream->ReadLine(line, &hasMoreLines);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// The file is corrupted ?
|
||||
// FIXME: in case we implement a version 2, we should inform the user using
|
||||
// the console about this issue.
|
||||
if (!line.EqualsLiteral(SERVICEWORKERREGISTRAR_VERSION)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
while (hasMoreLines) {
|
||||
ServiceWorkerRegistrationData* entry = mData.AppendElement();
|
||||
|
||||
#define GET_LINE(x) \
|
||||
rv = lineInputStream->ReadLine(x, &hasMoreLines); \
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { \
|
||||
return rv; \
|
||||
} \
|
||||
if (NS_WARN_IF(!hasMoreLines)) { \
|
||||
return NS_ERROR_FAILURE; \
|
||||
}
|
||||
|
||||
GET_LINE(line);
|
||||
|
||||
if (line.EqualsLiteral(SERVICEWORKERREGISTRAR_SYSTEM_PRINCIPAL)) {
|
||||
entry->principal() = mozilla::ipc::SystemPrincipalInfo();
|
||||
} else {
|
||||
if (!line.EqualsLiteral(SERVICEWORKERREGISTRAR_CONTENT_PRINCIPAL)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
GET_LINE(line);
|
||||
|
||||
uint32_t appId = line.ToInteger(&rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
GET_LINE(line);
|
||||
|
||||
if (!line.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE) &&
|
||||
!line.EqualsLiteral(SERVICEWORKERREGISTRAR_FALSE)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
bool isInBrowserElement = line.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE);
|
||||
|
||||
GET_LINE(line);
|
||||
entry->principal() =
|
||||
mozilla::ipc::ContentPrincipalInfo(appId, isInBrowserElement,
|
||||
line);
|
||||
}
|
||||
|
||||
GET_LINE(entry->scope());
|
||||
GET_LINE(entry->scriptSpec());
|
||||
GET_LINE(entry->currentWorkerURL());
|
||||
|
||||
#undef GET_LINE
|
||||
|
||||
rv = lineInputStream->ReadLine(line, &hasMoreLines);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!line.EqualsLiteral(SERVICEWORKERREGISTRAR_TERMINATOR)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerRegistrar::DeleteData()
|
||||
{
|
||||
// We cannot assert about the correct thread because normally this method
|
||||
// runs on a IO thread, but in gTests we call it from the main-thread.
|
||||
|
||||
MOZ_ASSERT(mProfileDir);
|
||||
|
||||
{
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
mData.Clear();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
nsresult rv = mProfileDir->Clone(getter_AddRefs(file));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
rv = file->Append(NS_LITERAL_STRING(SERVICEWORKERREGISTRAR_FILE));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
rv = file->Remove(false);
|
||||
if (rv == NS_ERROR_FILE_NOT_FOUND) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
class ServiceWorkerRegistrarSaveDataRunnable MOZ_FINAL : public nsRunnable
|
||||
{
|
||||
public:
|
||||
ServiceWorkerRegistrarSaveDataRunnable()
|
||||
: mThread(do_GetCurrentThread())
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Run()
|
||||
{
|
||||
nsRefPtr<ServiceWorkerRegistrar> service = ServiceWorkerRegistrar::Get();
|
||||
MOZ_ASSERT(service);
|
||||
|
||||
service->SaveData();
|
||||
|
||||
nsRefPtr<nsRunnable> runnable =
|
||||
NS_NewRunnableMethod(service, &ServiceWorkerRegistrar::DataSaved);
|
||||
nsresult rv = mThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIThread> mThread;
|
||||
};
|
||||
|
||||
void
|
||||
ServiceWorkerRegistrar::ScheduleSaveData()
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(!mShuttingDown);
|
||||
|
||||
nsCOMPtr<nsIEventTarget> target =
|
||||
do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
|
||||
MOZ_ASSERT(target, "Must have stream transport service");
|
||||
|
||||
nsRefPtr<nsRunnable> runnable =
|
||||
new ServiceWorkerRegistrarSaveDataRunnable();
|
||||
nsresult rv = target->Dispatch(runnable, NS_DISPATCH_NORMAL);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
++mRunnableCounter;
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerRegistrar::ShutdownCompleted()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
MOZ_ASSERT(mShutdownCompleteFlag && !*mShutdownCompleteFlag);
|
||||
*mShutdownCompleteFlag = true;
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerRegistrar::SaveData()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
nsresult rv = WriteData();
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to write data for the ServiceWorker Registations.");
|
||||
DeleteData();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerRegistrar::DataSaved()
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(mRunnableCounter);
|
||||
|
||||
--mRunnableCounter;
|
||||
MaybeScheduleShutdownCompleted();
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerRegistrar::MaybeScheduleShutdownCompleted()
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
if (mRunnableCounter || !mShuttingDown) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<nsRunnable> runnable =
|
||||
NS_NewRunnableMethod(this, &ServiceWorkerRegistrar::ShutdownCompleted);
|
||||
nsresult rv = NS_DispatchToMainThread(runnable);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
ServiceWorkerRegistrar::WriteData()
|
||||
{
|
||||
// We cannot assert about the correct thread because normally this method
|
||||
// runs on a IO thread, but in gTests we call it from the main-thread.
|
||||
|
||||
MOZ_ASSERT(mProfileDir);
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
nsresult rv = mProfileDir->Clone(getter_AddRefs(file));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = file->Append(NS_LITERAL_STRING(SERVICEWORKERREGISTRAR_FILE));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// We need a lock to take a snapshot of the data.
|
||||
nsTArray<ServiceWorkerRegistrationData> data;
|
||||
{
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
data = mData;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIOutputStream> stream;
|
||||
rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(stream), file);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsAutoCString buffer;
|
||||
buffer.AppendLiteral(SERVICEWORKERREGISTRAR_VERSION);
|
||||
buffer.Append('\n');
|
||||
|
||||
uint32_t count;
|
||||
rv = stream->Write(buffer.Data(), buffer.Length(), &count);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (count != buffer.Length()) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0, len = data.Length(); i < len; ++i) {
|
||||
const mozilla::ipc::PrincipalInfo& info = data[i].principal();
|
||||
|
||||
if (info.type() == mozilla::ipc::PrincipalInfo::TSystemPrincipalInfo) {
|
||||
buffer.AssignLiteral(SERVICEWORKERREGISTRAR_SYSTEM_PRINCIPAL);
|
||||
} else {
|
||||
MOZ_ASSERT(info.type() == mozilla::ipc::PrincipalInfo::TContentPrincipalInfo);
|
||||
|
||||
const mozilla::ipc::ContentPrincipalInfo& cInfo =
|
||||
info.get_ContentPrincipalInfo();
|
||||
|
||||
buffer.AssignLiteral(SERVICEWORKERREGISTRAR_CONTENT_PRINCIPAL);
|
||||
buffer.Append('\n');
|
||||
|
||||
buffer.AppendInt(cInfo.appId());
|
||||
buffer.Append('\n');
|
||||
|
||||
if (cInfo.isInBrowserElement()) {
|
||||
buffer.AppendLiteral(SERVICEWORKERREGISTRAR_TRUE);
|
||||
} else {
|
||||
buffer.AppendLiteral(SERVICEWORKERREGISTRAR_FALSE);
|
||||
}
|
||||
|
||||
buffer.Append('\n');
|
||||
buffer.Append(cInfo.spec());
|
||||
}
|
||||
|
||||
buffer.Append('\n');
|
||||
|
||||
buffer.Append(data[i].scope());
|
||||
buffer.Append('\n');
|
||||
|
||||
buffer.Append(data[i].scriptSpec());
|
||||
buffer.Append('\n');
|
||||
|
||||
buffer.Append(data[i].currentWorkerURL());
|
||||
buffer.Append('\n');
|
||||
|
||||
buffer.AppendLiteral(SERVICEWORKERREGISTRAR_TERMINATOR);
|
||||
buffer.Append('\n');
|
||||
|
||||
rv = stream->Write(buffer.Data(), buffer.Length(), &count);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (count != buffer.Length()) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(stream);
|
||||
MOZ_ASSERT(safeStream);
|
||||
|
||||
rv = safeStream->Finish();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerRegistrar::ProfileStarted()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mProfileDir);
|
||||
|
||||
nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
|
||||
getter_AddRefs(mProfileDir));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIEventTarget> target =
|
||||
do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
|
||||
MOZ_ASSERT(target, "Must have stream transport service");
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
NS_NewRunnableMethod(this, &ServiceWorkerRegistrar::LoadData);
|
||||
rv = target->Dispatch(runnable, NS_DISPATCH_NORMAL);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to dispatch the LoadDataRunnable.");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerRegistrar::ProfileStopped()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!mProfileDir) {
|
||||
nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
|
||||
getter_AddRefs(mProfileDir));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PBackgroundChild* child = BackgroundChild::GetForCurrentThread();
|
||||
if (!child) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool completed = false;
|
||||
mShutdownCompleteFlag = &completed;
|
||||
|
||||
child->SendShutdownServiceWorkerRegistrar();
|
||||
|
||||
nsCOMPtr<nsIThread> thread(do_GetCurrentThread());
|
||||
while (true) {
|
||||
MOZ_ALWAYS_TRUE(NS_ProcessNextEvent(thread));
|
||||
if (completed) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerRegistrar::Shutdown()
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(!mShuttingDown);
|
||||
|
||||
mShuttingDown = true;
|
||||
MaybeScheduleShutdownCompleted();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerRegistrar::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
const char16_t* aData)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!strcmp(aTopic, "profile-after-change")) {
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
services::GetObserverService();
|
||||
observerService->RemoveObserver(this, "profile-after-change");
|
||||
|
||||
// The profile is fully loaded, now we can proceed with the loading of data
|
||||
// from disk.
|
||||
ProfileStarted();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!strcmp(aTopic, "profile-before-change")) {
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
services::GetObserverService();
|
||||
observerService->RemoveObserver(this, "profile-before-change");
|
||||
|
||||
// Shutting down, let's sync the data.
|
||||
ProfileStopped();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(false, "ServiceWorkerRegistrar got unexpected topic!");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
92
dom/workers/ServiceWorkerRegistrar.h
Normal file
92
dom/workers/ServiceWorkerRegistrar.h
Normal file
@ -0,0 +1,92 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_workers_ServiceWorkerRegistrar_h
|
||||
#define mozilla_dom_workers_ServiceWorkerRegistrar_h
|
||||
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
#define SERVICEWORKERREGISTRAR_FILE "serviceworker.txt"
|
||||
#define SERVICEWORKERREGISTRAR_VERSION "1"
|
||||
#define SERVICEWORKERREGISTRAR_TERMINATOR "#"
|
||||
#define SERVICEWORKERREGISTRAR_TRUE "true"
|
||||
#define SERVICEWORKERREGISTRAR_FALSE "false"
|
||||
#define SERVICEWORKERREGISTRAR_SYSTEM_PRINCIPAL "system"
|
||||
#define SERVICEWORKERREGISTRAR_CONTENT_PRINCIPAL "content"
|
||||
|
||||
|
||||
class nsIFile;
|
||||
class nsRunnable;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class ServiceWorkerRegistrationData;
|
||||
|
||||
class ServiceWorkerRegistrar : public nsIObserver
|
||||
{
|
||||
friend class ServiceWorkerRegistrarSaveDataRunnable;
|
||||
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
static void Initialize();
|
||||
|
||||
void Shutdown();
|
||||
|
||||
void DataSaved();
|
||||
|
||||
static already_AddRefed<ServiceWorkerRegistrar> Get();
|
||||
|
||||
void GetRegistrations(nsTArray<ServiceWorkerRegistrationData>& aValues);
|
||||
|
||||
void RegisterServiceWorker(const ServiceWorkerRegistrationData& aData);
|
||||
void UnregisterServiceWorker(const nsACString& aScope);
|
||||
|
||||
protected:
|
||||
// These methods are protected because we test this class using gTest
|
||||
// subclassing it.
|
||||
void LoadData();
|
||||
void SaveData();
|
||||
|
||||
nsresult ReadData();
|
||||
nsresult WriteData();
|
||||
void DeleteData();
|
||||
|
||||
ServiceWorkerRegistrar();
|
||||
virtual ~ServiceWorkerRegistrar();
|
||||
|
||||
private:
|
||||
void ProfileStarted();
|
||||
void ProfileStopped();
|
||||
|
||||
void ScheduleSaveData();
|
||||
void ShutdownCompleted();
|
||||
void MaybeScheduleShutdownCompleted();
|
||||
|
||||
mozilla::Monitor mMonitor;
|
||||
|
||||
protected:
|
||||
// mData and mDataLoaded are protected by mMonitor.
|
||||
nsTArray<ServiceWorkerRegistrationData> mData;
|
||||
bool mDataLoaded;
|
||||
|
||||
bool mShuttingDown;
|
||||
bool* mShutdownCompleteFlag;
|
||||
uint32_t mRunnableCounter;
|
||||
|
||||
nsCOMPtr<nsIFile> mProfileDir;
|
||||
};
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
||||
|
||||
#endif // mozilla_dom_workers_ServiceWorkerRegistrar_h
|
21
dom/workers/ServiceWorkerRegistrarTypes.ipdlh
Normal file
21
dom/workers/ServiceWorkerRegistrarTypes.ipdlh
Normal file
@ -0,0 +1,21 @@
|
||||
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
|
||||
/* vim: set sw=4 ts=8 et tw=80 ft=cpp : */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
include PBackgroundSharedTypes;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
struct ServiceWorkerRegistrationData
|
||||
{
|
||||
nsCString scope;
|
||||
nsCString scriptSpec;
|
||||
nsCString currentWorkerURL;
|
||||
PrincipalInfo principal;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
@ -200,7 +200,7 @@ ServiceWorkerRegistration::Unregister(ErrorResult& aRv)
|
||||
nsRefPtr<UnregisterCallback> cb = new UnregisterCallback(promise);
|
||||
|
||||
NS_ConvertUTF8toUTF16 scope(uriSpec);
|
||||
aRv = swm->Unregister(cb, scope);
|
||||
aRv = swm->Unregister(documentPrincipal, cb, scope);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -590,7 +590,7 @@ public:
|
||||
// We don't need to check if the principal can load this mScope because a
|
||||
// ServiceWorkerGlobalScope can always unregister itself.
|
||||
|
||||
rv = swm->Unregister(this, mScope);
|
||||
rv = swm->Unregister(mWorkerPrivate->GetPrincipal(), this, mScope);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
UnregisterFailed();
|
||||
return NS_OK;
|
||||
|
@ -9,6 +9,7 @@ EXPORTS.mozilla.dom += [
|
||||
'ServiceWorkerCommon.h',
|
||||
'ServiceWorkerContainer.h',
|
||||
'ServiceWorkerEvents.h',
|
||||
'ServiceWorkerRegistrar.h',
|
||||
'ServiceWorkerRegistration.h',
|
||||
'WorkerPrivate.h',
|
||||
'WorkerRunnable.h',
|
||||
@ -66,6 +67,7 @@ UNIFIED_SOURCES += [
|
||||
'ServiceWorkerContainer.cpp',
|
||||
'ServiceWorkerEvents.cpp',
|
||||
'ServiceWorkerManager.cpp',
|
||||
'ServiceWorkerRegistrar.cpp',
|
||||
'ServiceWorkerRegistration.cpp',
|
||||
'SharedWorker.cpp',
|
||||
'URL.cpp',
|
||||
@ -78,6 +80,10 @@ UNIFIED_SOURCES += [
|
||||
'XMLHttpRequestUpload.cpp',
|
||||
]
|
||||
|
||||
IPDL_SOURCES += [
|
||||
'ServiceWorkerRegistrarTypes.ipdlh',
|
||||
]
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
||||
MSVC_ENABLE_PGO = True
|
||||
@ -108,3 +114,5 @@ MOCHITEST_MANIFESTS += [
|
||||
MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
|
||||
|
||||
XPCSHELL_TESTS_MANIFESTS += ['test/xpcshell/xpcshell.ini']
|
||||
|
||||
TEST_DIRS += ['test/gtest']
|
||||
|
282
dom/workers/test/gtest/TestReadWrite.cpp
Normal file
282
dom/workers/test/gtest/TestReadWrite.cpp
Normal file
@ -0,0 +1,282 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "mozilla/dom/ServiceWorkerRegistrar.h"
|
||||
#include "mozilla/dom/ServiceWorkerRegistrarTypes.h"
|
||||
#include "mozilla/ipc/PBackgroundSharedTypes.h"
|
||||
|
||||
#include "nsAppDirectoryServiceDefs.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
class ServiceWorkerRegistrarTest : public ServiceWorkerRegistrar
|
||||
{
|
||||
public:
|
||||
ServiceWorkerRegistrarTest()
|
||||
{
|
||||
nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
|
||||
getter_AddRefs(mProfileDir));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult TestReadData() { return ReadData(); }
|
||||
nsresult TestWriteData() { return WriteData(); }
|
||||
void TestDeleteData() { DeleteData(); }
|
||||
|
||||
nsTArray<ServiceWorkerRegistrationData>& TestGetData() { return mData; }
|
||||
};
|
||||
|
||||
already_AddRefed<nsIFile>
|
||||
GetFile()
|
||||
{
|
||||
nsCOMPtr<nsIFile> file;
|
||||
nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
|
||||
getter_AddRefs(file));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
file->Append(NS_LITERAL_STRING(SERVICEWORKERREGISTRAR_FILE));
|
||||
return file.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
CreateFile(const nsACString& aData)
|
||||
{
|
||||
nsCOMPtr<nsIFile> file = GetFile();
|
||||
|
||||
nsCOMPtr<nsIOutputStream> stream;
|
||||
nsresult rv = NS_NewLocalFileOutputStream(getter_AddRefs(stream), file);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t count;
|
||||
rv = stream->Write(aData.Data(), aData.Length(), &count);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (count != aData.Length()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST(ServiceWorkerRegistrar, TestNoFile)
|
||||
{
|
||||
nsCOMPtr<nsIFile> file = GetFile();
|
||||
ASSERT_TRUE(file) << "GetFile must return a nsIFIle";
|
||||
|
||||
bool exists;
|
||||
nsresult rv = file->Exists(&exists);
|
||||
ASSERT_EQ(NS_OK, rv) << "nsIFile::Exists cannot fail";
|
||||
|
||||
if (exists) {
|
||||
rv = file->Remove(false);
|
||||
ASSERT_EQ(NS_OK, rv) << "nsIFile::Remove cannot fail";
|
||||
}
|
||||
|
||||
nsRefPtr<ServiceWorkerRegistrarTest> swr = new ServiceWorkerRegistrarTest;
|
||||
|
||||
rv = swr->TestReadData();
|
||||
ASSERT_EQ(NS_OK, rv) << "ReadData() should not fail";
|
||||
|
||||
const nsTArray<ServiceWorkerRegistrationData>& data = swr->TestGetData();
|
||||
ASSERT_EQ((uint32_t)0, data.Length()) << "No data should be found in an empty file";
|
||||
}
|
||||
|
||||
TEST(ServiceWorkerRegistrar, TestEmptyFile)
|
||||
{
|
||||
ASSERT_TRUE(CreateFile(EmptyCString())) << "CreateFile should not fail";
|
||||
|
||||
nsRefPtr<ServiceWorkerRegistrarTest> swr = new ServiceWorkerRegistrarTest;
|
||||
|
||||
nsresult rv = swr->TestReadData();
|
||||
ASSERT_NE(NS_OK, rv) << "ReadData() should fail if the file is empty";
|
||||
|
||||
const nsTArray<ServiceWorkerRegistrationData>& data = swr->TestGetData();
|
||||
ASSERT_EQ((uint32_t)0, data.Length()) << "No data should be found in an empty file";
|
||||
}
|
||||
|
||||
TEST(ServiceWorkerRegistrar, TestRightVersionFile)
|
||||
{
|
||||
ASSERT_TRUE(CreateFile(nsAutoCString(SERVICEWORKERREGISTRAR_VERSION "\n"))) << "CreateFile should not fail";
|
||||
|
||||
nsRefPtr<ServiceWorkerRegistrarTest> swr = new ServiceWorkerRegistrarTest;
|
||||
|
||||
nsresult rv = swr->TestReadData();
|
||||
ASSERT_EQ(NS_OK, rv) << "ReadData() should not fail when the version is correct";
|
||||
|
||||
const nsTArray<ServiceWorkerRegistrationData>& data = swr->TestGetData();
|
||||
ASSERT_EQ((uint32_t)0, data.Length()) << "No data should be found in an empty file";
|
||||
}
|
||||
|
||||
TEST(ServiceWorkerRegistrar, TestWrongVersionFile)
|
||||
{
|
||||
ASSERT_TRUE(CreateFile(nsAutoCString(SERVICEWORKERREGISTRAR_VERSION "bla\n"))) << "CreateFile should not fail";
|
||||
|
||||
nsRefPtr<ServiceWorkerRegistrarTest> swr = new ServiceWorkerRegistrarTest;
|
||||
|
||||
nsresult rv = swr->TestReadData();
|
||||
ASSERT_NE(NS_OK, rv) << "ReadData() should fail when the version is not correct";
|
||||
|
||||
const nsTArray<ServiceWorkerRegistrationData>& data = swr->TestGetData();
|
||||
ASSERT_EQ((uint32_t)0, data.Length()) << "No data should be found in an empty file";
|
||||
}
|
||||
|
||||
TEST(ServiceWorkerRegistrar, TestReadData)
|
||||
{
|
||||
nsAutoCString buffer(SERVICEWORKERREGISTRAR_VERSION "\n");
|
||||
|
||||
buffer.Append(SERVICEWORKERREGISTRAR_SYSTEM_PRINCIPAL "\n");
|
||||
buffer.Append("scope 0\nscriptSpec 0\ncurrentWorkerURL 0\n");
|
||||
buffer.Append(SERVICEWORKERREGISTRAR_TERMINATOR "\n");
|
||||
|
||||
buffer.Append(SERVICEWORKERREGISTRAR_CONTENT_PRINCIPAL "\n");
|
||||
buffer.Append("123\n" SERVICEWORKERREGISTRAR_TRUE "\n");
|
||||
buffer.Append("spec 1\nscope 1\nscriptSpec 1\ncurrentWorkerURL 1\n");
|
||||
buffer.Append(SERVICEWORKERREGISTRAR_TERMINATOR "\n");
|
||||
|
||||
buffer.Append(SERVICEWORKERREGISTRAR_CONTENT_PRINCIPAL "\n");
|
||||
buffer.Append("0\n" SERVICEWORKERREGISTRAR_FALSE "\n");
|
||||
buffer.Append("spec 2\nscope 2\nscriptSpec 2\ncurrentWorkerURL 2\n");
|
||||
buffer.Append(SERVICEWORKERREGISTRAR_TERMINATOR "\n");
|
||||
|
||||
ASSERT_TRUE(CreateFile(buffer)) << "CreateFile should not fail";
|
||||
|
||||
nsRefPtr<ServiceWorkerRegistrarTest> swr = new ServiceWorkerRegistrarTest;
|
||||
|
||||
nsresult rv = swr->TestReadData();
|
||||
ASSERT_EQ(NS_OK, rv) << "ReadData() should not fail";
|
||||
|
||||
const nsTArray<ServiceWorkerRegistrationData>& data = swr->TestGetData();
|
||||
ASSERT_EQ((uint32_t)3, data.Length()) << "4 entries should be found";
|
||||
|
||||
const mozilla::ipc::PrincipalInfo& info0 = data[0].principal();
|
||||
ASSERT_EQ(info0.type(), mozilla::ipc::PrincipalInfo::TSystemPrincipalInfo) << "First principal must be system";
|
||||
|
||||
ASSERT_STREQ("scope 0", data[0].scope().get());
|
||||
ASSERT_STREQ("scriptSpec 0", data[0].scriptSpec().get());
|
||||
ASSERT_STREQ("currentWorkerURL 0", data[0].currentWorkerURL().get());
|
||||
|
||||
const mozilla::ipc::PrincipalInfo& info1 = data[1].principal();
|
||||
ASSERT_EQ(info1.type(), mozilla::ipc::PrincipalInfo::TContentPrincipalInfo) << "First principal must be content";
|
||||
const mozilla::ipc::ContentPrincipalInfo& cInfo1 = data[1].principal();
|
||||
|
||||
ASSERT_EQ((uint32_t)123, cInfo1.appId());
|
||||
ASSERT_EQ((uint32_t)true, cInfo1.isInBrowserElement());
|
||||
ASSERT_STREQ("spec 1", cInfo1.spec().get());
|
||||
ASSERT_STREQ("scope 1", data[1].scope().get());
|
||||
ASSERT_STREQ("scriptSpec 1", data[1].scriptSpec().get());
|
||||
ASSERT_STREQ("currentWorkerURL 1", data[1].currentWorkerURL().get());
|
||||
|
||||
const mozilla::ipc::PrincipalInfo& info2 = data[2].principal();
|
||||
ASSERT_EQ(info2.type(), mozilla::ipc::PrincipalInfo::TContentPrincipalInfo) << "First principal must be content";
|
||||
const mozilla::ipc::ContentPrincipalInfo& cInfo2 = data[2].principal();
|
||||
|
||||
ASSERT_EQ((uint32_t)0, cInfo2.appId());
|
||||
ASSERT_EQ((uint32_t)false, cInfo2.isInBrowserElement());
|
||||
ASSERT_STREQ("spec 2", cInfo2.spec().get());
|
||||
ASSERT_STREQ("scope 2", data[2].scope().get());
|
||||
ASSERT_STREQ("scriptSpec 2", data[2].scriptSpec().get());
|
||||
ASSERT_STREQ("currentWorkerURL 2", data[2].currentWorkerURL().get());
|
||||
}
|
||||
|
||||
TEST(ServiceWorkerRegistrar, TestDeleteData)
|
||||
{
|
||||
ASSERT_TRUE(CreateFile(nsAutoCString("Foobar"))) << "CreateFile should not fail";
|
||||
|
||||
nsRefPtr<ServiceWorkerRegistrarTest> swr = new ServiceWorkerRegistrarTest;
|
||||
|
||||
swr->TestDeleteData();
|
||||
|
||||
nsCOMPtr<nsIFile> file = GetFile();
|
||||
|
||||
bool exists;
|
||||
nsresult rv = file->Exists(&exists);
|
||||
ASSERT_EQ(NS_OK, rv) << "nsIFile::Exists cannot fail";
|
||||
|
||||
ASSERT_FALSE(exists) << "The file should not exist after a DeleteData().";
|
||||
}
|
||||
|
||||
TEST(ServiceWorkerRegistrar, TestWriteData)
|
||||
{
|
||||
{
|
||||
nsRefPtr<ServiceWorkerRegistrarTest> swr = new ServiceWorkerRegistrarTest;
|
||||
|
||||
nsTArray<ServiceWorkerRegistrationData>& data = swr->TestGetData();
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
ServiceWorkerRegistrationData* d = data.AppendElement();
|
||||
|
||||
if ((i % 2) == 0) {
|
||||
d->principal() = mozilla::ipc::SystemPrincipalInfo();
|
||||
} else if ((i % 2) == 1) {
|
||||
nsAutoCString spec;
|
||||
spec.AppendPrintf("spec write %d", i);
|
||||
d->principal() = mozilla::ipc::ContentPrincipalInfo(i, i % 2, spec);
|
||||
}
|
||||
|
||||
d->scope().AppendPrintf("scope write %d", i);
|
||||
d->scriptSpec().AppendPrintf("scriptSpec write %d", i);
|
||||
d->currentWorkerURL().AppendPrintf("currentWorkerURL write %d", i);
|
||||
}
|
||||
|
||||
nsresult rv = swr->TestWriteData();
|
||||
ASSERT_EQ(NS_OK, rv) << "WriteData() should not fail";
|
||||
}
|
||||
|
||||
nsRefPtr<ServiceWorkerRegistrarTest> swr = new ServiceWorkerRegistrarTest;
|
||||
|
||||
nsresult rv = swr->TestReadData();
|
||||
ASSERT_EQ(NS_OK, rv) << "ReadData() should not fail";
|
||||
|
||||
const nsTArray<ServiceWorkerRegistrationData>& data = swr->TestGetData();
|
||||
ASSERT_EQ((uint32_t)10, data.Length()) << "10 entries should be found";
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
nsAutoCString test;
|
||||
|
||||
if ((i % 2) == 0) {
|
||||
ASSERT_EQ(data[i].principal().type(), mozilla::ipc::PrincipalInfo::TSystemPrincipalInfo);
|
||||
} else if ((i % 2) == 1) {
|
||||
ASSERT_EQ(data[i].principal().type(), mozilla::ipc::PrincipalInfo::TContentPrincipalInfo);
|
||||
const mozilla::ipc::ContentPrincipalInfo& cInfo = data[i].principal();
|
||||
|
||||
ASSERT_EQ((uint32_t)i, cInfo.appId());
|
||||
ASSERT_EQ((uint32_t)(i %2), cInfo.isInBrowserElement());
|
||||
|
||||
test.AppendPrintf("spec write %d", i);
|
||||
ASSERT_STREQ(test.get(), cInfo.spec().get());
|
||||
}
|
||||
|
||||
test.Truncate();
|
||||
test.AppendPrintf("scope write %d", i);
|
||||
ASSERT_STREQ(test.get(), data[i].scope().get());
|
||||
|
||||
test.Truncate();
|
||||
test.AppendPrintf("scriptSpec write %d", i);
|
||||
ASSERT_STREQ(test.get(), data[i].scriptSpec().get());
|
||||
|
||||
test.Truncate();
|
||||
test.AppendPrintf("currentWorkerURL write %d", i);
|
||||
ASSERT_STREQ(test.get(), data[i].currentWorkerURL().get());
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
int rv = RUN_ALL_TESTS();
|
||||
return rv;
|
||||
}
|
13
dom/workers/test/gtest/moz.build
Normal file
13
dom/workers/test/gtest/moz.build
Normal file
@ -0,0 +1,13 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, you can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
UNIFIED_SOURCES = [
|
||||
'TestReadWrite.cpp',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul-gtest'
|
@ -10,10 +10,12 @@
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/PBlobParent.h"
|
||||
#include "mozilla/dom/ServiceWorkerRegistrar.h"
|
||||
#include "mozilla/dom/indexedDB/ActorsParent.h"
|
||||
#include "mozilla/dom/ipc/BlobParent.h"
|
||||
#include "mozilla/ipc/BackgroundParent.h"
|
||||
#include "mozilla/ipc/BackgroundUtils.h"
|
||||
#include "mozilla/ipc/PBackgroundSharedTypes.h"
|
||||
#include "mozilla/ipc/PBackgroundTestParent.h"
|
||||
#include "mozilla/layout/VsyncParent.h"
|
||||
#include "nsNetUtil.h"
|
||||
@ -71,6 +73,7 @@ namespace ipc {
|
||||
|
||||
using mozilla::dom::ContentParent;
|
||||
using mozilla::dom::BroadcastChannelParent;
|
||||
using mozilla::dom::ServiceWorkerRegistrationData;
|
||||
|
||||
BackgroundParentImpl::BackgroundParentImpl()
|
||||
{
|
||||
@ -353,6 +356,197 @@ BackgroundParentImpl::DeallocPBroadcastChannelParent(
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class RegisterServiceWorkerCallback MOZ_FINAL : public nsRunnable
|
||||
{
|
||||
public:
|
||||
explicit RegisterServiceWorkerCallback(
|
||||
const ServiceWorkerRegistrationData& aData)
|
||||
: mData(aData)
|
||||
{
|
||||
AssertIsInMainProcess();
|
||||
AssertIsOnBackgroundThread();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Run()
|
||||
{
|
||||
AssertIsInMainProcess();
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
nsRefPtr<dom::ServiceWorkerRegistrar> service =
|
||||
dom::ServiceWorkerRegistrar::Get();
|
||||
MOZ_ASSERT(service);
|
||||
|
||||
service->RegisterServiceWorker(mData);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
ServiceWorkerRegistrationData mData;
|
||||
};
|
||||
|
||||
class UnregisterServiceWorkerCallback MOZ_FINAL : public nsRunnable
|
||||
{
|
||||
public:
|
||||
explicit UnregisterServiceWorkerCallback(const nsString& aScope)
|
||||
: mScope(aScope)
|
||||
{
|
||||
AssertIsInMainProcess();
|
||||
AssertIsOnBackgroundThread();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Run()
|
||||
{
|
||||
AssertIsInMainProcess();
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
nsRefPtr<dom::ServiceWorkerRegistrar> service =
|
||||
dom::ServiceWorkerRegistrar::Get();
|
||||
MOZ_ASSERT(service);
|
||||
|
||||
service->UnregisterServiceWorker(NS_ConvertUTF16toUTF8(mScope));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsString mScope;
|
||||
};
|
||||
|
||||
class CheckPrincipalWithCallbackRunnable MOZ_FINAL : public nsRunnable
|
||||
{
|
||||
public:
|
||||
CheckPrincipalWithCallbackRunnable(already_AddRefed<ContentParent> aParent,
|
||||
const PrincipalInfo& aPrincipalInfo,
|
||||
nsRunnable* aCallback)
|
||||
: mContentParent(aParent)
|
||||
, mPrincipalInfo(aPrincipalInfo)
|
||||
, mCallback(aCallback)
|
||||
, mBackgroundThread(NS_GetCurrentThread())
|
||||
{
|
||||
AssertIsInMainProcess();
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
MOZ_ASSERT(mContentParent);
|
||||
MOZ_ASSERT(mCallback);
|
||||
MOZ_ASSERT(mBackgroundThread);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP Run()
|
||||
{
|
||||
if (NS_IsMainThread()) {
|
||||
nsCOMPtr<nsIPrincipal> principal = PrincipalInfoToPrincipal(mPrincipalInfo);
|
||||
AssertAppPrincipal(mContentParent, principal);
|
||||
mContentParent = nullptr;
|
||||
|
||||
mBackgroundThread->Dispatch(this, NS_DISPATCH_NORMAL);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
AssertIsOnBackgroundThread();
|
||||
mCallback->Run();
|
||||
mCallback = nullptr;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<ContentParent> mContentParent;
|
||||
PrincipalInfo mPrincipalInfo;
|
||||
nsRefPtr<nsRunnable> mCallback;
|
||||
nsCOMPtr<nsIThread> mBackgroundThread;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
bool
|
||||
BackgroundParentImpl::RecvRegisterServiceWorker(
|
||||
const ServiceWorkerRegistrationData& aData)
|
||||
{
|
||||
AssertIsInMainProcess();
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
// Basic validation.
|
||||
if (aData.scope().IsEmpty() ||
|
||||
aData.scriptSpec().IsEmpty() ||
|
||||
aData.principal().type() == PrincipalInfo::TNullPrincipalInfo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsRefPtr<RegisterServiceWorkerCallback> callback =
|
||||
new RegisterServiceWorkerCallback(aData);
|
||||
|
||||
nsRefPtr<ContentParent> parent = BackgroundParent::GetContentParent(this);
|
||||
|
||||
// If the ContentParent is null we are dealing with a same-process actor.
|
||||
if (!parent) {
|
||||
callback->Run();
|
||||
return true;
|
||||
}
|
||||
|
||||
nsRefPtr<CheckPrincipalWithCallbackRunnable> runnable =
|
||||
new CheckPrincipalWithCallbackRunnable(parent.forget(), aData.principal(),
|
||||
callback);
|
||||
nsresult rv = NS_DispatchToMainThread(runnable);
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(rv));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BackgroundParentImpl::RecvUnregisterServiceWorker(
|
||||
const PrincipalInfo& aPrincipalInfo,
|
||||
const nsString& aScope)
|
||||
{
|
||||
AssertIsInMainProcess();
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
// Basic validation.
|
||||
if (aScope.IsEmpty() ||
|
||||
aPrincipalInfo.type() == PrincipalInfo::TNullPrincipalInfo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsRefPtr<UnregisterServiceWorkerCallback> callback =
|
||||
new UnregisterServiceWorkerCallback(aScope);
|
||||
|
||||
nsRefPtr<ContentParent> parent = BackgroundParent::GetContentParent(this);
|
||||
|
||||
// If the ContentParent is null we are dealing with a same-process actor.
|
||||
if (!parent) {
|
||||
callback->Run();
|
||||
return true;
|
||||
}
|
||||
|
||||
nsRefPtr<CheckPrincipalWithCallbackRunnable> runnable =
|
||||
new CheckPrincipalWithCallbackRunnable(parent.forget(), aPrincipalInfo,
|
||||
callback);
|
||||
nsresult rv = NS_DispatchToMainThread(runnable);
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(rv));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BackgroundParentImpl::RecvShutdownServiceWorkerRegistrar()
|
||||
{
|
||||
AssertIsInMainProcess();
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
if (BackgroundParent::IsOtherProcessActor(this)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsRefPtr<dom::ServiceWorkerRegistrar> service =
|
||||
dom::ServiceWorkerRegistrar::Get();
|
||||
MOZ_ASSERT(service);
|
||||
|
||||
service->Shutdown();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -83,6 +83,17 @@ protected:
|
||||
|
||||
virtual bool
|
||||
DeallocPBroadcastChannelParent(PBroadcastChannelParent* aActor) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
RecvRegisterServiceWorker(const ServiceWorkerRegistrationData& aData)
|
||||
MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
RecvUnregisterServiceWorker(const PrincipalInfo& aPrincipalInfo,
|
||||
const nsString& aScope) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
RecvShutdownServiceWorkerRegistrar() MOZ_OVERRIDE;
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
|
@ -12,6 +12,7 @@ include protocol PVsync;
|
||||
include DOMTypes;
|
||||
include PBackgroundSharedTypes;
|
||||
include PBackgroundIDBSharedTypes;
|
||||
include ServiceWorkerRegistrarTypes;
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
@ -35,6 +36,11 @@ parent:
|
||||
|
||||
PBroadcastChannel(PrincipalInfo pInfo, nsString origin, nsString channel);
|
||||
|
||||
RegisterServiceWorker(ServiceWorkerRegistrationData data);
|
||||
UnregisterServiceWorker(PrincipalInfo principalInfo,
|
||||
nsString scope);
|
||||
ShutdownServiceWorkerRegistrar();
|
||||
|
||||
both:
|
||||
PBlob(BlobConstructorParams params);
|
||||
|
||||
|
@ -301,6 +301,8 @@ nsLayoutStatics::Initialize()
|
||||
|
||||
IMEStateManager::Init();
|
||||
|
||||
ServiceWorkerRegistrar::Initialize();
|
||||
|
||||
#ifdef MOZ_B2G
|
||||
RequestSyncWifiService::Init();
|
||||
#endif
|
||||
|
@ -7039,6 +7039,13 @@
|
||||
"n_values": 3,
|
||||
"description": "Doorhanger shown = 0, Disable = 1, Enable = 2"
|
||||
},
|
||||
"SERVICE_WORKER_REGISTRATION_LOADING": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
"high": "5000",
|
||||
"n_buckets": 20,
|
||||
"description": "Tracking how ServiceWorkerRegistrar loads data before the first content is shown"
|
||||
},
|
||||
"LOOP_CLIENT_CALL_URL_REQUESTS_SUCCESS": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "boolean",
|
||||
|
Loading…
Reference in New Issue
Block a user