Bug 1089778 - ServiceWorkerRegistration is keyed by scope for event dispatch and invalidation. r=baku

--HG--
extra : rebase_source : 012bcfa0aef20bc6b79e030cb7439f03799e9370
This commit is contained in:
Nikhil Marathe 2014-10-27 11:52:57 -07:00
parent 04d493a8bc
commit 076d17e308
7 changed files with 63 additions and 66 deletions

View File

@ -17,7 +17,7 @@ interface nsIServiceWorkerUnregisterCallback : nsISupports
[noscript] void UnregisterFailed();
};
[builtinclass, uuid(78fdfe7c-0e2c-4157-ac6e-3952b61df36a)]
[builtinclass, uuid(430f02bf-63d0-44ab-9a59-7bd49c608949)]
interface nsIServiceWorkerManager : nsISupports
{
/**
@ -50,8 +50,8 @@ interface nsIServiceWorkerManager : nsISupports
void removeReadyPromise(in nsIDOMWindow aWindow);
// aTarget MUST be a ServiceWorkerRegistration.
[noscript] void AddRegistrationEventListener(in nsIURI aPageURI, in nsIDOMEventTarget aTarget);
[noscript] void RemoveRegistrationEventListener(in nsIURI aPageURI, in nsIDOMEventTarget aTarget);
[noscript] void AddRegistrationEventListener(in DOMString aScope, in nsIDOMEventTarget aTarget);
[noscript] void RemoveRegistrationEventListener(in DOMString aScope, in nsIDOMEventTarget aTarget);
/**
* Call this to request that document `aDoc` be controlled by a ServiceWorker

View File

@ -1689,14 +1689,19 @@ ServiceWorkerManager::GetScopeForUrl(const nsAString& aUrl, nsAString& aScope)
}
NS_IMETHODIMP
ServiceWorkerManager::AddRegistrationEventListener(nsIURI* aDocumentURI, nsIDOMEventTarget* aListener)
ServiceWorkerManager::AddRegistrationEventListener(const nsAString& aScope, nsIDOMEventTarget* aListener)
{
MOZ_ASSERT(aDocumentURI);
AssertIsOnMainThread();
nsRefPtr<ServiceWorkerDomainInfo> domainInfo = GetDomainInfo(aDocumentURI);
nsAutoCString scope = NS_ConvertUTF16toUTF8(aScope);
nsRefPtr<ServiceWorkerDomainInfo> domainInfo = GetDomainInfo(scope);
if (!domainInfo) {
nsCOMPtr<nsIURI> scopeAsURI;
nsresult rv = NS_NewURI(getter_AddRefs(scopeAsURI), scope, nullptr, nullptr);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsAutoCString domain;
nsresult rv = aDocumentURI->GetHost(domain);
rv = scopeAsURI->GetHost(domain);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -1710,22 +1715,36 @@ ServiceWorkerManager::AddRegistrationEventListener(nsIURI* aDocumentURI, nsIDOME
// TODO: this is very very bad:
ServiceWorkerRegistration* registration = static_cast<ServiceWorkerRegistration*>(aListener);
MOZ_ASSERT(!domainInfo->mServiceWorkerRegistrations.Contains(registration));
#ifdef DEBUG
// Ensure a registration is only listening for it's own scope.
nsAutoString regScope;
registration->GetScope(regScope);
MOZ_ASSERT(!regScope.IsEmpty());
MOZ_ASSERT(scope.Equals(NS_ConvertUTF16toUTF8(regScope)));
#endif
domainInfo->mServiceWorkerRegistrations.AppendElement(registration);
return NS_OK;
}
NS_IMETHODIMP
ServiceWorkerManager::RemoveRegistrationEventListener(nsIURI* aDocumentURI, nsIDOMEventTarget* aListener)
ServiceWorkerManager::RemoveRegistrationEventListener(const nsAString& aScope, nsIDOMEventTarget* aListener)
{
AssertIsOnMainThread();
MOZ_ASSERT(aDocumentURI);
nsRefPtr<ServiceWorkerDomainInfo> domainInfo = GetDomainInfo(aDocumentURI);
nsCString scope = NS_ConvertUTF16toUTF8(aScope);
nsRefPtr<ServiceWorkerDomainInfo> domainInfo = GetDomainInfo(scope);
if (!domainInfo) {
return NS_OK;
}
ServiceWorkerRegistration* registration = static_cast<ServiceWorkerRegistration*>(aListener);
MOZ_ASSERT(domainInfo->mServiceWorkerRegistrations.Contains(registration));
#ifdef DEBUG
// Ensure a registration is unregistering for it's own scope.
nsAutoString regScope;
registration->GetScope(regScope);
MOZ_ASSERT(!regScope.IsEmpty());
MOZ_ASSERT(scope.Equals(NS_ConvertUTF16toUTF8(regScope)));
#endif
domainInfo->mServiceWorkerRegistrations.RemoveElement(registration);
return NS_OK;
}
@ -1737,31 +1756,21 @@ ServiceWorkerManager::FireEventOnServiceWorkerRegistrations(
{
AssertIsOnMainThread();
nsRefPtr<ServiceWorkerDomainInfo> domainInfo =
GetDomainInfo(aRegistration->mScriptSpec);
GetDomainInfo(aRegistration->mScope);
if (domainInfo) {
nsTObserverArray<ServiceWorkerRegistration*>::ForwardIterator it(domainInfo->mServiceWorkerRegistrations);
while (it.HasMore()) {
nsRefPtr<ServiceWorkerRegistration> target = it.GetNext();
nsIURI* targetURI = target->GetDocumentURI();
if (!targetURI) {
NS_WARNING("Controlled domain cannot have page with null URI!");
continue;
}
nsAutoString regScope;
target->GetScope(regScope);
MOZ_ASSERT(!regScope.IsEmpty());
nsCString path;
nsresult rv = targetURI->GetSpec(path);
if (NS_WARN_IF(NS_FAILED(rv))) {
continue;
NS_ConvertUTF16toUTF8 utf8Scope(regScope);
if (utf8Scope.Equals(aRegistration->mScope)) {
nsresult rv = target->DispatchTrustedEvent(aName);
NS_WARN_IF(NS_FAILED(rv));
}
nsCString scope = FindScopeForPath(domainInfo->mOrderedScopes, path);
if (scope.IsEmpty() ||
!scope.Equals(aRegistration->mScope)) {
continue;
}
target->DispatchTrustedEvent(aName);
}
}
}
@ -1787,7 +1796,7 @@ ServiceWorkerManager::GetServiceWorkerForScope(nsIDOMWindow* aWindow,
///////////////////////////////////////////
// Security check
nsCString scope = NS_ConvertUTF16toUTF8(aScope);
nsAutoCString scope = NS_ConvertUTF16toUTF8(aScope);
nsCOMPtr<nsIURI> scopeURI;
// We pass nullptr as the base URI since scopes obtained from
// ServiceWorkerRegistrations MUST be fully qualified URIs.
@ -1990,21 +1999,15 @@ ServiceWorkerManager::InvalidateServiceWorkerRegistrationWorker(ServiceWorkerReg
nsTObserverArray<ServiceWorkerRegistration*>::ForwardIterator it(domainInfo->mServiceWorkerRegistrations);
while (it.HasMore()) {
nsRefPtr<ServiceWorkerRegistration> target = it.GetNext();
nsAutoString regScope;
target->GetScope(regScope);
MOZ_ASSERT(!regScope.IsEmpty());
nsIURI* targetURI = target->GetDocumentURI();
nsCString path;
nsresult rv = targetURI->GetSpec(path);
if (NS_WARN_IF(NS_FAILED(rv))) {
continue;
NS_ConvertUTF16toUTF8 utf8Scope(regScope);
if (utf8Scope.Equals(aRegistration->mScope)) {
target->InvalidateWorkerReference(aWhichOnes);
}
nsCString scope = FindScopeForPath(domainInfo->mOrderedScopes, path);
if (scope.IsEmpty() ||
!scope.Equals(aRegistration->mScope)) {
continue;
}
target->InvalidateWorkerReference(aWhichOnes);
}
}
}

View File

@ -342,7 +342,6 @@ public:
void
FinishFetch(ServiceWorkerRegistrationInfo* aRegistration);
void
HandleError(JSContext* aCx,
const nsACString& aScope,

View File

@ -271,7 +271,7 @@ ServiceWorkerRegistration::StartListeningForEvents()
{
nsCOMPtr<nsIServiceWorkerManager> swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID);
if (swm) {
swm->AddRegistrationEventListener(GetDocumentURI(), this);
swm->AddRegistrationEventListener(mScope, this);
mListeningForEvents = true;
}
}
@ -285,17 +285,10 @@ ServiceWorkerRegistration::StopListeningForEvents()
nsCOMPtr<nsIServiceWorkerManager> swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID);
if (swm) {
swm->RemoveRegistrationEventListener(GetDocumentURI(), this);
swm->RemoveRegistrationEventListener(mScope, this);
mListeningForEvents = false;
}
}
nsIURI*
ServiceWorkerRegistration::GetDocumentURI() const
{
MOZ_ASSERT(GetOwner());
return GetOwner()->GetDocumentURI();
}
} // dom namespace
} // mozilla namespace

View File

@ -55,10 +55,6 @@ public:
Unregister(ErrorResult& aRv);
// Useful methods for ServiceWorkerManager:
nsIURI*
GetDocumentURI() const;
void
InvalidateWorkerReference(WhichServiceWorker aWhichOnes);

View File

@ -19,7 +19,7 @@
for (var i = 0; i < a.length; ++i) {
window.parent.postMessage({ type: "check", status: a[i] instanceof ServiceWorkerRegistration,
msg: "getRegistrations returns an array of ServiceWorkerRegistration objects" }, "*");
if (a[i].scope.match(/simpleregister\/\*/)) {
if (a[i].scope.match(/simpleregister\//)) {
a[i].onupdatefound = function(e) {
eventReceived();
}

View File

@ -16,23 +16,29 @@
<script class="testbody" type="text/javascript">
function simpleRegister() {
var p = navigator.serviceWorker.register("worker.js", { scope: "./" });
var p = navigator.serviceWorker.register("worker.js", { scope: "./install_event" });
return p;
}
function nextRegister(reg) {
var p = navigator.serviceWorker.register("install_event_worker.js", { scope: "./" });
return new Promise(function(resolve, reject) {
reg.onupdatefound = function(e) {
ok(true, "Received onupdatefound");
resolve();
};
ok(reg instanceof ServiceWorkerRegistration, "reg should be a ServiceWorkerRegistration");
var p = navigator.serviceWorker.register("install_event_worker.js", { scope: "./install_event" });
return p.then(function(swr) {
ok(reg.scope === swr.scope, "Scope for registrations should match.");
return new Promise(function(resolve, reject) {
swr.addEventListener('updatefound', function(e) {
ok(true, "Received onupdatefound");
resolve();
});
});
}, function(e) {
ok(false, "Unexpected Error in nextRegister! " + e);
});
}
function unregister() {
return navigator.serviceWorker.getRegistration("./").then(function(reg) {
return navigator.serviceWorker.getRegistration("./install_event").then(function(reg) {
return reg.unregister();
});
}