Bug 1185716 - Unregistering a service worker should drop its push subscription. r=bkelly

MozReview-Commit-ID: A5MtdADIQVV

--HG--
extra : rebase_source : 2a87866053ee500a245b5496c8810e19bd9490ee
This commit is contained in:
Kit Cambridge 2016-05-03 11:44:40 -07:00
parent 0f4166d532
commit c90a3eecfc
3 changed files with 109 additions and 51 deletions

View File

@ -10,6 +10,7 @@ http://creativecommons.org/licenses/publicdomain/
<head>
<title>Test for Bug 1170817</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
<script type="text/javascript" src="/tests/dom/push/test/test_utils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
@ -24,65 +25,54 @@ http://creativecommons.org/licenses/publicdomain/
<script class="testbody" type="text/javascript">
function generateURL() {
return "worker.js" + "?" + (Math.random());
}
var registration;
add_task(function* start() {
yield setupPrefsAndMockSocket(new MockWebSocket());
yield setPushPermission(true);
function start() {
return navigator.serviceWorker.register("worker.js" + "?" + (Math.random()), {scope: "."})
.then(swr => { registration = swr; return swr; });
}
registration = yield navigator.serviceWorker.register(
generateURL(), {scope: "."});
});
function unregisterSW() {
return registration.unregister().then(function(result) {
ok(result, "Unregister should return true.");
}, function(e) {
dump("Unregistering the SW failed with " + e + "\n");
});
}
var pushSubscription;
add_task(function* setupPushNotification() {
pushSubscription = yield registration.pushManager.subscribe();
ok(pushSubscription, "successful registered for push notification");
});
function setupPushNotification(swr) {
return swr.pushManager.subscribe().then(
pushSubscription => {
ok(true, "successful registered for push notification");
return pushSubscription;
}, error => {
ok(false, "could not register for push notification");
});
}
add_task(function* unregisterPushNotification() {
var result = yield pushSubscription.unsubscribe();
ok(result, "unsubscribe() on existing subscription should return true.");
});
function unregisterPushNotification(pushSubscription) {
return pushSubscription.unsubscribe().then(
result => {
ok(result, "unsubscribe() on existing subscription should return true.");
return pushSubscription;
}, error => {
ok(false, "unsubscribe() should never fail.");
});
}
add_task(function* unregisterAgain() {
var result = yield pushSubscription.unsubscribe();
ok(!result, "unsubscribe() on previously unsubscribed subscription should return false.");
});
function unregisterAgain(pushSubscription) {
return pushSubscription.unsubscribe().then(
result => {
ok(!result, "unsubscribe() on previously unsubscribed subscription should return false.");
return pushSubscription;
}, error => {
ok(false, "unsubscribe() should never fail.");
});
}
add_task(function* subscribeAgain() {
pushSubscription = yield registration.pushManager.subscribe();
ok(pushSubscription, "Should create a new push subscription");
function runTest() {
start()
.then(setupPushNotification)
.then(unregisterPushNotification)
.then(unregisterAgain)
.then(unregisterSW)
.catch(function(e) {
ok(false, "Some test failed with error " + e);
}).then(SimpleTest.finish);
}
var result = yield registration.unregister();
ok(result, "Should unregister the service worker");
registration = yield navigator.serviceWorker.register(
generateURL(), {scope: "."});
var pushSubscription = yield registration.pushManager.getSubscription();
ok(!pushSubscription,
"Unregistering a service worker should drop its subscription");
});
add_task(function* unregister() {
var result = yield registration.unregister();
ok(result, "Unregister should return true.");
});
setupPrefsAndMockSocket(new MockWebSocket()).then(_ => runTest());
SpecialPowers.addPermission("desktop-notification", true, document);
SimpleTest.waitForExplicitFinish();
</script>
</body>
</html>

View File

@ -6,10 +6,44 @@
#include "ServiceWorkerUnregisterJob.h"
#include "nsIPushService.h"
namespace mozilla {
namespace dom {
namespace workers {
class ServiceWorkerUnregisterJob::PushUnsubscribeCallback final :
public nsIUnsubscribeResultCallback
{
public:
NS_DECL_ISUPPORTS
explicit PushUnsubscribeCallback(ServiceWorkerUnregisterJob* aJob)
: mJob(aJob)
{
AssertIsOnMainThread();
}
NS_IMETHODIMP
OnUnsubscribe(nsresult aStatus, bool) override
{
// Warn if unsubscribing fails, but don't prevent the worker from
// unregistering.
Unused << NS_WARN_IF(NS_FAILED(aStatus));
mJob->Unregister();
return NS_OK;
}
private:
~PushUnsubscribeCallback()
{
}
RefPtr<ServiceWorkerUnregisterJob> mJob;
};
NS_IMPL_ISUPPORTS(ServiceWorkerUnregisterJob::PushUnsubscribeCallback,
nsIUnsubscribeResultCallback)
ServiceWorkerUnregisterJob::ServiceWorkerUnregisterJob(nsIPrincipal* aPrincipal,
const nsACString& aScope,
@ -41,6 +75,35 @@ ServiceWorkerUnregisterJob::AsyncExecute()
return;
}
// Push API, section 5: "When a service worker registration is unregistered,
// any associated push subscription must be deactivated." To ensure the
// service worker registration isn't cleared as we're unregistering, we
// unsubscribe first.
nsCOMPtr<nsIPushService> pushService =
do_GetService("@mozilla.org/push/Service;1");
if (NS_WARN_IF(!pushService)) {
Unregister();
return;
}
nsCOMPtr<nsIUnsubscribeResultCallback> unsubscribeCallback =
new PushUnsubscribeCallback(this);
nsresult rv = pushService->Unsubscribe(NS_ConvertUTF8toUTF16(mScope),
mPrincipal, unsubscribeCallback);
if (NS_WARN_IF(NS_FAILED(rv))) {
Unregister();
}
}
void
ServiceWorkerUnregisterJob::Unregister()
{
AssertIsOnMainThread();
if (Canceled()) {
Finish(NS_ERROR_DOM_ABORT_ERR);
return;
}
// Step 1 of the Unregister algorithm requires checking that the
// client origin matches the scope's origin. We perform this in
// registration->update() method directly since we don't have that

View File

@ -24,11 +24,16 @@ public:
GetResult() const;
private:
class PushUnsubscribeCallback;
virtual ~ServiceWorkerUnregisterJob();
virtual void
AsyncExecute() override;
void
Unregister();
bool mResult;
bool mSendToParent;
};