Add support for unregistering a service worker
authorcdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 25 Oct 2017 18:28:54 +0000 (18:28 +0000)
committercdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 25 Oct 2017 18:28:54 +0000 (18:28 +0000)
https://bugs.webkit.org/show_bug.cgi?id=178735

Reviewed by Brady Eidson.

Source/WebCore:

Add support for unregistering a service worker:
- https://w3c.github.io/ServiceWorker/#navigator-service-worker-unregister

Test: http/tests/workers/service/basic-unregister.https.html

* workers/service/ServiceWorkerContainer.cpp:
(WebCore::ServiceWorkerContainer::addRegistration):
(WebCore::ServiceWorkerContainer::removeRegistration):
(WebCore::ServiceWorkerContainer::jobResolvedWithUnregistrationResult):
* workers/service/ServiceWorkerContainer.h:
* workers/service/ServiceWorkerJob.cpp:
(WebCore::ServiceWorkerJob::resolvedWithUnregistrationResult):
* workers/service/ServiceWorkerJob.h:
* workers/service/ServiceWorkerJobClient.h:
* workers/service/ServiceWorkerJobData.h:
(WebCore::ServiceWorkerJobData::encode const):
(WebCore::ServiceWorkerJobData::decode):
* workers/service/ServiceWorkerJobType.h:
* workers/service/ServiceWorkerRegistration.cpp:
(WebCore::containerForScriptExecutionContext):
(WebCore::ServiceWorkerRegistration::unregister):
* workers/service/server/SWClientConnection.cpp:
(WebCore::SWClientConnection::registrationJobResolvedInServer):
(WebCore::SWClientConnection::unregistrationJobResolvedInServer):
* workers/service/server/SWClientConnection.h:
* workers/service/server/SWServer.cpp:
(WebCore::SWServer::resolveRegistationJob):
(WebCore::SWServer::resolveUnregistrationJob):
* workers/service/server/SWServer.h:
* workers/service/server/SWServerRegistration.cpp:
(WebCore::SWServerRegistration::scriptContextStarted):
(WebCore::SWServerRegistration::startNextJob):
(WebCore::SWServerRegistration::runUnregisterJob):
(WebCore::SWServerRegistration::resolveWithRegistrationOnMainThread):
(WebCore::SWServerRegistration::resolveWithUnregistrationResultOnMainThread):
(WebCore::SWServerRegistration::resolveCurrentRegistrationJob):
(WebCore::SWServerRegistration::resolveCurrentUnregistrationJob):
* workers/service/server/SWServerRegistration.h:

Source/WebKit:

Add support for unregistering a service worker:
- https://w3c.github.io/ServiceWorker/#navigator-service-worker-unregister

* StorageProcess/ServiceWorker/WebSWServerConnection.cpp:
(WebKit::WebSWServerConnection::resolveRegistrationJobInClient):
(WebKit::WebSWServerConnection::resolveUnregistrationJobInClient):
* StorageProcess/ServiceWorker/WebSWServerConnection.h:
* WebProcess/Storage/WebSWClientConnection.messages.in:

LayoutTests:

Add layout test coverage.

* http/tests/workers/service/basic-unregister.https-expected.txt: Added.
* http/tests/workers/service/basic-unregister.https.html: Added.
* http/tests/workers/service/resources/basic-unregister.js: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@223964 268f45cc-cd09-0410-ab3c-d52691b4dbfc

23 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/workers/service/basic-unregister.https-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/workers/service/basic-unregister.https.html [new file with mode: 0644]
LayoutTests/http/tests/workers/service/resources/basic-unregister.js [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/workers/service/ServiceWorkerContainer.cpp
Source/WebCore/workers/service/ServiceWorkerContainer.h
Source/WebCore/workers/service/ServiceWorkerJob.cpp
Source/WebCore/workers/service/ServiceWorkerJob.h
Source/WebCore/workers/service/ServiceWorkerJobClient.h
Source/WebCore/workers/service/ServiceWorkerJobData.h
Source/WebCore/workers/service/ServiceWorkerJobType.h
Source/WebCore/workers/service/ServiceWorkerRegistration.cpp
Source/WebCore/workers/service/server/SWClientConnection.cpp
Source/WebCore/workers/service/server/SWClientConnection.h
Source/WebCore/workers/service/server/SWServer.cpp
Source/WebCore/workers/service/server/SWServer.h
Source/WebCore/workers/service/server/SWServerRegistration.cpp
Source/WebCore/workers/service/server/SWServerRegistration.h
Source/WebKit/ChangeLog
Source/WebKit/StorageProcess/ServiceWorker/WebSWServerConnection.cpp
Source/WebKit/StorageProcess/ServiceWorker/WebSWServerConnection.h
Source/WebKit/WebProcess/Storage/WebSWClientConnection.messages.in

index 2dd65f2..f54cea9 100644 (file)
@@ -1,3 +1,16 @@
+2017-10-25  Chris Dumez  <cdumez@apple.com>
+
+        Add support for unregistering a service worker
+        https://bugs.webkit.org/show_bug.cgi?id=178735
+
+        Reviewed by Brady Eidson.
+
+        Add layout test coverage.
+
+        * http/tests/workers/service/basic-unregister.https-expected.txt: Added.
+        * http/tests/workers/service/basic-unregister.https.html: Added.
+        * http/tests/workers/service/resources/basic-unregister.js: Added.
+
 2017-10-25  Andy Estes  <aestes@apple.com>
 
         [Payment Request] Implement the "user aborts the payment request" algorithm
diff --git a/LayoutTests/http/tests/workers/service/basic-unregister.https-expected.txt b/LayoutTests/http/tests/workers/service/basic-unregister.https-expected.txt
new file mode 100644 (file)
index 0000000..fe63648
--- /dev/null
@@ -0,0 +1,10 @@
+PASS: There is initially no service worker registered for the origin
+PASS: registration scope is https://127.0.0.1:8443/workers/service/
+PASS: There is a service worker registered for the origin
+PASS: Unregistration was successful
+PASS: There is no service worker registered for the origin
+PASS: Unregistration failed as expected
+PASS: There is no service worker registered for the origin
+PASS: registration scope is https://127.0.0.1:8443/workers/service/
+PASS: There is a service worker registered for the origin
+
diff --git a/LayoutTests/http/tests/workers/service/basic-unregister.https.html b/LayoutTests/http/tests/workers/service/basic-unregister.https.html
new file mode 100644 (file)
index 0000000..2b3a453
--- /dev/null
@@ -0,0 +1,9 @@
+<html>
+<head>
+<script src="resources/sw-test-pre.js"></script>
+</head>
+<body>
+
+<script src="resources/basic-unregister.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/workers/service/resources/basic-unregister.js b/LayoutTests/http/tests/workers/service/resources/basic-unregister.js
new file mode 100644 (file)
index 0000000..f0eef71
--- /dev/null
@@ -0,0 +1,63 @@
+function done()
+{
+    finishSWTest();
+}
+
+async function test()
+{
+    try {
+        if (!internals.hasServiceWorkerRegisteredForOrigin(self.origin))
+            log("PASS: There is initially no service worker registered for the origin");
+        else
+            log("FAIL: There is initially a service worker registered for the origin");
+
+        let registration = await navigator.serviceWorker.register("resources/basic-fetch-worker.js", { });
+        if (registration.scope === "https://127.0.0.1:8443/workers/service/")
+            log("PASS: registration scope is " + registration.scope);
+        else
+            log("FAIL: registration scope is " + registration.scope);
+        if (internals.hasServiceWorkerRegisteredForOrigin(self.origin))
+            log("PASS: There is a service worker registered for the origin");
+        else
+            log("FAIL: There is no service worker registered for the origin");
+
+        let unregistrationResult = await registration.unregister();
+        if (unregistrationResult)
+            log("PASS: Unregistration was successful");
+        else
+            log("FAIL: Unregistration failed");
+
+        if (!internals.hasServiceWorkerRegisteredForOrigin(self.origin))
+            log("PASS: There is no service worker registered for the origin");
+        else
+            log("FAIL: There is a service worker registered for the origin");
+
+        unregistrationResult = await registration.unregister();
+        if (!unregistrationResult)
+            log("PASS: Unregistration failed as expected");
+        else
+            log("FAIL: Unregistration succeeded unexpectedly");
+        
+        if (!internals.hasServiceWorkerRegisteredForOrigin(self.origin))
+            log("PASS: There is no service worker registered for the origin");
+        else
+            log("FAIL: There is a service worker registered for the origin");
+
+        registration = await navigator.serviceWorker.register("resources/basic-fetch-worker.js", { });
+        if (registration.scope === "https://127.0.0.1:8443/workers/service/")
+            log("PASS: registration scope is " + registration.scope);
+        else
+            log("FAIL: registration scope is " + registration.scope);
+
+        if (internals.hasServiceWorkerRegisteredForOrigin(self.origin))
+            log("PASS: There is a service worker registered for the origin");
+        else
+            log("FAIL: There is no service worker registered for the origin");
+    } catch(e) {
+        console.log("Got exception: " + e);
+    }
+    finishSWTest();
+}
+
+test();
index 0f2f231..ffa1eb7 100644 (file)
@@ -1,3 +1,49 @@
+2017-10-25  Chris Dumez  <cdumez@apple.com>
+
+        Add support for unregistering a service worker
+        https://bugs.webkit.org/show_bug.cgi?id=178735
+
+        Reviewed by Brady Eidson.
+
+        Add support for unregistering a service worker:
+        - https://w3c.github.io/ServiceWorker/#navigator-service-worker-unregister
+
+        Test: http/tests/workers/service/basic-unregister.https.html
+
+        * workers/service/ServiceWorkerContainer.cpp:
+        (WebCore::ServiceWorkerContainer::addRegistration):
+        (WebCore::ServiceWorkerContainer::removeRegistration):
+        (WebCore::ServiceWorkerContainer::jobResolvedWithUnregistrationResult):
+        * workers/service/ServiceWorkerContainer.h:
+        * workers/service/ServiceWorkerJob.cpp:
+        (WebCore::ServiceWorkerJob::resolvedWithUnregistrationResult):
+        * workers/service/ServiceWorkerJob.h:
+        * workers/service/ServiceWorkerJobClient.h:
+        * workers/service/ServiceWorkerJobData.h:
+        (WebCore::ServiceWorkerJobData::encode const):
+        (WebCore::ServiceWorkerJobData::decode):
+        * workers/service/ServiceWorkerJobType.h:
+        * workers/service/ServiceWorkerRegistration.cpp:
+        (WebCore::containerForScriptExecutionContext):
+        (WebCore::ServiceWorkerRegistration::unregister):
+        * workers/service/server/SWClientConnection.cpp:
+        (WebCore::SWClientConnection::registrationJobResolvedInServer):
+        (WebCore::SWClientConnection::unregistrationJobResolvedInServer):
+        * workers/service/server/SWClientConnection.h:
+        * workers/service/server/SWServer.cpp:
+        (WebCore::SWServer::resolveRegistationJob):
+        (WebCore::SWServer::resolveUnregistrationJob):
+        * workers/service/server/SWServer.h:
+        * workers/service/server/SWServerRegistration.cpp:
+        (WebCore::SWServerRegistration::scriptContextStarted):
+        (WebCore::SWServerRegistration::startNextJob):
+        (WebCore::SWServerRegistration::runUnregisterJob):
+        (WebCore::SWServerRegistration::resolveWithRegistrationOnMainThread):
+        (WebCore::SWServerRegistration::resolveWithUnregistrationResultOnMainThread):
+        (WebCore::SWServerRegistration::resolveCurrentRegistrationJob):
+        (WebCore::SWServerRegistration::resolveCurrentUnregistrationJob):
+        * workers/service/server/SWServerRegistration.h:
+
 2017-10-25  Simon Fraser  <simon.fraser@apple.com>
 
         MediaSessionManager* needs to catch Obj-C exceptions
index 56d56c7..713ce03 100644 (file)
@@ -90,17 +90,18 @@ void ServiceWorkerContainer::addRegistration(const String& relativeScriptURL, co
     auto* context = scriptExecutionContext();
     if (!context || !context->sessionID().isValid()) {
         ASSERT_NOT_REACHED();
+        promise->reject(Exception(InvalidStateError));
         return;
     }
 
-    if (!m_swConnection)
-        m_swConnection = &ServiceWorkerProvider::singleton().serviceWorkerConnectionForSession(context->sessionID());
-
     if (relativeScriptURL.isEmpty()) {
         promise->reject(Exception { TypeError, ASCIILiteral("serviceWorker.register() cannot be called with an empty script URL") });
         return;
     }
 
+    if (!m_swConnection)
+        m_swConnection = &ServiceWorkerProvider::singleton().serviceWorkerConnectionForSession(scriptExecutionContext()->sessionID());
+
     ServiceWorkerJobData jobData(m_swConnection->identifier());
 
     jobData.scriptURL = context->completeURL(relativeScriptURL);
@@ -144,6 +145,30 @@ void ServiceWorkerContainer::addRegistration(const String& relativeScriptURL, co
     scheduleJob(ServiceWorkerJob::create(*this, WTFMove(promise), WTFMove(jobData)));
 }
 
+void ServiceWorkerContainer::removeRegistration(const URL& scopeURL, Ref<DeferredPromise>&& promise)
+{
+    auto* context = scriptExecutionContext();
+    if (!context || !context->sessionID().isValid()) {
+        ASSERT_NOT_REACHED();
+        promise->reject(Exception(InvalidStateError));
+        return;
+    }
+
+    if (!m_swConnection) {
+        ASSERT_NOT_REACHED();
+        promise->reject(Exception(InvalidStateError));
+        return;
+    }
+
+    ServiceWorkerJobData jobData(m_swConnection->identifier());
+    jobData.clientCreationURL = context->url();
+    jobData.topOrigin = SecurityOriginData::fromSecurityOrigin(context->topOrigin());
+    jobData.type = ServiceWorkerJobType::Unregister;
+    jobData.scopeURL = scopeURL;
+
+    scheduleJob(ServiceWorkerJob::create(*this, WTFMove(promise), WTFMove(jobData)));
+}
+
 void ServiceWorkerContainer::scheduleJob(Ref<ServiceWorkerJob>&& job)
 {
     ASSERT(m_swConnection);
@@ -194,6 +219,25 @@ void ServiceWorkerContainer::jobResolvedWithRegistration(ServiceWorkerJob& job,
     job.promise().resolve<IDLInterface<ServiceWorkerRegistration>>(registration.get());
 }
 
+void ServiceWorkerContainer::jobResolvedWithUnregistrationResult(ServiceWorkerJob& job, bool unregistrationResult)
+{
+    ScopeGuard guard([this, &job] {
+        jobDidFinish(job);
+    });
+
+    auto* context = scriptExecutionContext();
+    if (!context) {
+        LOG_ERROR("ServiceWorkerContainer::jobResolvedWithUnregistrationResult called but the containers ScriptExecutionContext is gone");
+        return;
+    }
+
+    // FIXME: Implement proper selection of service workers.
+    if (unregistrationResult)
+        context->setSelectedServiceWorkerIdentifier(0);
+
+    job.promise().resolve<IDLBoolean>(unregistrationResult);
+}
+
 void ServiceWorkerContainer::startScriptFetchForJob(ServiceWorkerJob& job)
 {
     LOG(ServiceWorker, "SeviceWorkerContainer %p starting script fetch for job %" PRIu64, this, job.data().identifier());
index ae6da1b..290199f 100644 (file)
@@ -60,6 +60,7 @@ public:
     ReadyPromise& ready() { return m_readyPromise; }
 
     void addRegistration(const String& scriptURL, const RegistrationOptions&, Ref<DeferredPromise>&&);
+    void removeRegistration(const URL& scopeURL, Ref<DeferredPromise>&&);
     void getRegistration(const String& url, Ref<DeferredPromise>&&);
     void getRegistrations(Ref<DeferredPromise>&&);
 
@@ -73,6 +74,7 @@ private:
 
     void jobFailedWithException(ServiceWorkerJob&, const Exception&) final;
     void jobResolvedWithRegistration(ServiceWorkerJob&, ServiceWorkerRegistrationData&&) final;
+    void jobResolvedWithUnregistrationResult(ServiceWorkerJob&, bool unregistrationResult) final;
     void startScriptFetchForJob(ServiceWorkerJob&) final;
     void jobFinishedLoadingScript(ServiceWorkerJob&, const String&) final;
     void jobFailedLoadingScript(ServiceWorkerJob&, const ResourceError&) final;
index 62024b8..c35d357 100644 (file)
@@ -66,6 +66,15 @@ void ServiceWorkerJob::resolvedWithRegistration(ServiceWorkerRegistrationData&&
     m_client->jobResolvedWithRegistration(*this, WTFMove(data));
 }
 
+void ServiceWorkerJob::resolvedWithUnregistrationResult(bool unregistrationResult)
+{
+    ASSERT(currentThread() == m_creationThread);
+    ASSERT(!m_completed);
+
+    m_completed = true;
+    m_client->jobResolvedWithUnregistrationResult(*this, unregistrationResult);
+}
+
 void ServiceWorkerJob::startScriptFetch()
 {
     ASSERT(currentThread() == m_creationThread);
index 4bb6540..ae618da 100644 (file)
@@ -56,6 +56,7 @@ public:
 
     void failedWithException(const Exception&);
     void resolvedWithRegistration(ServiceWorkerRegistrationData&&);
+    void resolvedWithUnregistrationResult(bool);
     void startScriptFetch();
 
     ServiceWorkerJobData data() const { return m_jobData; }
index 852bfc3..858571b 100644 (file)
@@ -41,6 +41,7 @@ public:
 
     virtual void jobFailedWithException(ServiceWorkerJob&, const Exception&) = 0;
     virtual void jobResolvedWithRegistration(ServiceWorkerJob&, ServiceWorkerRegistrationData&&) = 0;
+    virtual void jobResolvedWithUnregistrationResult(ServiceWorkerJob&, bool unregistrationResult) = 0;
     virtual void startScriptFetchForJob(ServiceWorkerJob&) = 0;
     virtual void jobFinishedLoadingScript(ServiceWorkerJob&, const String&) = 0;
     virtual void jobFailedLoadingScript(ServiceWorkerJob&, const ResourceError&) = 0;
index a6d371a..c6c9936 100644 (file)
@@ -73,6 +73,8 @@ void ServiceWorkerJobData::encode(Encoder& encoder) const
     case ServiceWorkerJobType::Register:
         encoder << registrationOptions;
         break;
+    case ServiceWorkerJobType::Unregister:
+        break;
     }
 }
 
@@ -110,6 +112,8 @@ std::optional<ServiceWorkerJobData> ServiceWorkerJobData::decode(Decoder& decode
         if (!decoder.decode(jobData->registrationOptions))
             return std::nullopt;
         break;
+    case ServiceWorkerJobType::Unregister:
+        break;
     }
 
     return jobData;
index 4023fab..079f3e8 100644 (file)
@@ -31,6 +31,7 @@ namespace WebCore {
 
 enum class ServiceWorkerJobType {
     Register,
+    Unregister,
 };
 
 } // namespace WebCore
index cdae4b8..25919ab 100644 (file)
 #include "ServiceWorkerRegistration.h"
 
 #if ENABLE(SERVICE_WORKER)
+#include "DOMWindow.h"
+#include "Document.h"
+#include "Navigator.h"
+#include "ServiceWorkerContainer.h"
+#include "WorkerGlobalScope.h"
+#include "WorkerNavigator.h"
 
 namespace WebCore {
 
+static ServiceWorkerContainer* containerForScriptExecutionContext(ScriptExecutionContext& context)
+{
+    NavigatorBase* navigator = nullptr;
+    if (is<Document>(context)) {
+        if (auto* window = downcast<Document>(context).domWindow())
+            navigator = window->navigator();
+    } else
+        navigator = &downcast<WorkerGlobalScope>(context).navigator();
+
+    return navigator ? navigator->serviceWorker() : nullptr;
+}
+
 ServiceWorkerRegistration::ServiceWorkerRegistration(ScriptExecutionContext& context, ServiceWorkerRegistrationData&& registrationData)
     : ActiveDOMObject(&context)
     , m_registrationData(WTFMove(registrationData))
@@ -69,7 +87,20 @@ void ServiceWorkerRegistration::update(Ref<DeferredPromise>&& promise)
 
 void ServiceWorkerRegistration::unregister(Ref<DeferredPromise>&& promise)
 {
-    promise->reject(Exception(NotSupportedError, ASCIILiteral("ServiceWorkerRegistration::unregister not yet implemented")));
+    auto* context = scriptExecutionContext();
+    if (!context) {
+        ASSERT_NOT_REACHED();
+        promise->reject(Exception(InvalidStateError));
+        return;
+    }
+
+    auto* container = containerForScriptExecutionContext(*context);
+    if (!container) {
+        promise->reject(Exception(InvalidStateError));
+        return;
+    }
+
+    container->removeRegistration(m_registrationData.scopeURL, WTFMove(promise));
 }
 
 EventTargetInterface ServiceWorkerRegistration::eventTargetInterface() const
index 5d3433e..8e93c5e 100644 (file)
@@ -71,7 +71,7 @@ void SWClientConnection::jobRejectedInServer(uint64_t jobIdentifier, const Excep
     job->failedWithException(exceptionData.toException());
 }
 
-void SWClientConnection::jobResolvedInServer(uint64_t jobIdentifier, ServiceWorkerRegistrationData&& registrationData)
+void SWClientConnection::registrationJobResolvedInServer(uint64_t jobIdentifier, ServiceWorkerRegistrationData&& registrationData)
 {
     auto job = m_scheduledJobs.take(jobIdentifier);
     if (!job) {
@@ -82,6 +82,17 @@ void SWClientConnection::jobResolvedInServer(uint64_t jobIdentifier, ServiceWork
     job->resolvedWithRegistration(WTFMove(registrationData));
 }
 
+void SWClientConnection::unregistrationJobResolvedInServer(uint64_t jobIdentifier, bool unregistrationResult)
+{
+    auto job = m_scheduledJobs.take(jobIdentifier);
+    if (!job) {
+        LOG_ERROR("Job %" PRIu64 " resolved in server, but was not found", jobIdentifier);
+        return;
+    }
+
+    job->resolvedWithUnregistrationResult(unregistrationResult);
+}
+
 void SWClientConnection::startScriptFetchForServer(uint64_t jobIdentifier)
 {
     auto job = m_scheduledJobs.get(jobIdentifier);
index 4222b59..508a58a 100644 (file)
@@ -56,7 +56,8 @@ public:
 
 protected:
     WEBCORE_EXPORT void jobRejectedInServer(uint64_t jobIdentifier, const ExceptionData&);
-    WEBCORE_EXPORT void jobResolvedInServer(uint64_t jobIdentifier, ServiceWorkerRegistrationData&&);
+    WEBCORE_EXPORT void registrationJobResolvedInServer(uint64_t jobIdentifier, ServiceWorkerRegistrationData&&);
+    WEBCORE_EXPORT void unregistrationJobResolvedInServer(uint64_t jobIdentifier, bool unregistrationResult);
     WEBCORE_EXPORT void startScriptFetchForServer(uint64_t jobIdentifier);
 
 private:
index 07ae5fa..fba6503 100644 (file)
@@ -121,14 +121,23 @@ void SWServer::rejectJob(const ServiceWorkerJobData& jobData, const ExceptionDat
     connection->rejectJobInClient(jobData.identifier(), exceptionData);
 }
 
-void SWServer::resolveJob(const ServiceWorkerJobData& jobData, const ServiceWorkerRegistrationData& registrationData)
+void SWServer::resolveRegistrationJob(const ServiceWorkerJobData& jobData, const ServiceWorkerRegistrationData& registrationData)
 {
     LOG(ServiceWorker, "Resolved ServiceWorker job %" PRIu64 "-%" PRIu64 " in server with registration %" PRIu64, jobData.connectionIdentifier(), jobData.identifier(), registrationData.identifier);
     auto* connection = m_connections.get(jobData.connectionIdentifier());
     if (!connection)
         return;
 
-    connection->resolveJobInClient(jobData.identifier(), registrationData);
+    connection->resolveRegistrationJobInClient(jobData.identifier(), registrationData);
+}
+
+void SWServer::resolveUnregistrationJob(const ServiceWorkerJobData& jobData, const ServiceWorkerRegistrationKey& registrationKey, bool unregistrationResult)
+{
+    auto* connection = m_connections.get(jobData.connectionIdentifier());
+    if (!connection)
+        return;
+
+    connection->resolveUnregistrationJobInClient(jobData.identifier(), registrationKey, unregistrationResult);
 }
 
 void SWServer::startScriptFetch(const ServiceWorkerJobData& jobData)
index 1c1a2c9..c9669da 100644 (file)
@@ -67,7 +67,8 @@ public:
     private:
         // Messages to the client WebProcess
         virtual void rejectJobInClient(uint64_t jobIdentifier, const ExceptionData&) = 0;
-        virtual void resolveJobInClient(uint64_t jobIdentifier, const ServiceWorkerRegistrationData&) = 0;
+        virtual void resolveRegistrationJobInClient(uint64_t jobIdentifier, const ServiceWorkerRegistrationData&) = 0;
+        virtual void resolveUnregistrationJobInClient(uint64_t jobIdentifier, const ServiceWorkerRegistrationKey&, bool registrationResult) = 0;
         virtual void startScriptFetchInClient(uint64_t jobIdentifier) = 0;
 
         // Messages to the SW host WebProcess
@@ -81,7 +82,8 @@ public:
 
     void scheduleJob(const ServiceWorkerJobData&);
     void rejectJob(const ServiceWorkerJobData&, const ExceptionData&);
-    void resolveJob(const ServiceWorkerJobData&, const ServiceWorkerRegistrationData&);
+    void resolveRegistrationJob(const ServiceWorkerJobData&, const ServiceWorkerRegistrationData&);
+    void resolveUnregistrationJob(const ServiceWorkerJobData&, const ServiceWorkerRegistrationKey&, bool unregistrationResult);
     void startScriptFetch(const ServiceWorkerJobData&);
 
     void postTask(CrossThreadTask&&);
index 0d2178e..7d4cf89 100644 (file)
@@ -97,7 +97,7 @@ void SWServerRegistration::scriptContextFailedToStart(SWServer::Connection&, con
 void SWServerRegistration::scriptContextStarted(SWServer::Connection&, uint64_t identifier, const String& workerID)
 {
     UNUSED_PARAM(workerID);
-    resolveCurrentJob(ServiceWorkerRegistrationData { m_registrationKey, identifier, m_scopeURL, m_updateViaCache.value_or(ServiceWorkerUpdateViaCache::Imports) });
+    resolveCurrentRegistrationJob(ServiceWorkerRegistrationData { m_registrationKey, identifier, m_scopeURL, m_updateViaCache.value_or(ServiceWorkerUpdateViaCache::Imports) });
 }
 
 void SWServerRegistration::startNextJob()
@@ -112,6 +112,9 @@ void SWServerRegistration::startNextJob()
     case ServiceWorkerJobType::Register:
         m_server.postTask(createCrossThreadTask(*this, &SWServerRegistration::runRegisterJob, *m_currentJob));
         return;
+    case ServiceWorkerJobType::Unregister:
+        m_server.postTask(createCrossThreadTask(*this, &SWServerRegistration::runUnregisterJob, *m_currentJob));
+        return;
     }
 
     RELEASE_ASSERT_NOT_REACHED();
@@ -173,6 +176,29 @@ void SWServerRegistration::runRegisterJob(const ServiceWorkerJobData& job)
     runUpdateJob(job);
 }
 
+void SWServerRegistration::runUnregisterJob(const ServiceWorkerJobData& job)
+{
+    // If the origin of job’s scope url is not job's client's origin, then:
+    if (!protocolHostAndPortAreEqual(job.scopeURL, job.clientCreationURL))
+        return rejectWithExceptionOnMainThread(ExceptionData { SecurityError, ASCIILiteral("Origin of scope URL does not match the client's origin") });
+
+    // Let registration be the result of running "Get Registration" algorithm passing job’s scope url as the argument.
+    // If registration is null, then:
+    if (isEmpty() || m_uninstalling) {
+        // Invoke Resolve Job Promise with job and false.
+        resolveWithUnregistrationResultOnMainThread(false);
+        return;
+    }
+
+    // Set registration’s uninstalling flag.
+    m_uninstalling = true;
+
+    // Invoke Resolve Job Promise with job and true.
+    resolveWithUnregistrationResultOnMainThread(true);
+
+    // FIXME: Invoke Try Clear Registration with registration.
+}
+
 void SWServerRegistration::runUpdateJob(const ServiceWorkerJobData& job)
 {
     // If registration is null (in our parlance "empty") or registration’s uninstalling flag is set, then:
@@ -198,7 +224,13 @@ void SWServerRegistration::rejectWithExceptionOnMainThread(const ExceptionData&
 void SWServerRegistration::resolveWithRegistrationOnMainThread()
 {
     ASSERT(!isMainThread());
-    m_server.postTaskReply(createCrossThreadTask(*this, &SWServerRegistration::resolveCurrentJob, data()));
+    m_server.postTaskReply(createCrossThreadTask(*this, &SWServerRegistration::resolveCurrentRegistrationJob, data()));
+}
+
+void SWServerRegistration::resolveWithUnregistrationResultOnMainThread(bool unregistrationResult)
+{
+    ASSERT(!isMainThread());
+    m_server.postTaskReply(createCrossThreadTask(*this, &SWServerRegistration::resolveCurrentUnregistrationJob, unregistrationResult));
 }
 
 void SWServerRegistration::startScriptFetchFromMainThread()
@@ -217,12 +249,24 @@ void SWServerRegistration::rejectCurrentJob(const ExceptionData& exceptionData)
     finishCurrentJob();
 }
 
-void SWServerRegistration::resolveCurrentJob(const ServiceWorkerRegistrationData& data)
+void SWServerRegistration::resolveCurrentRegistrationJob(const ServiceWorkerRegistrationData& data)
+{
+    ASSERT(isMainThread());
+    ASSERT(m_currentJob);
+    ASSERT(m_currentJob->type == ServiceWorkerJobType::Register);
+
+    m_server.resolveRegistrationJob(*m_currentJob, data);
+
+    finishCurrentJob();
+}
+
+void SWServerRegistration::resolveCurrentUnregistrationJob(bool unregistrationResult)
 {
     ASSERT(isMainThread());
     ASSERT(m_currentJob);
+    ASSERT(m_currentJob->type == ServiceWorkerJobType::Unregister);
 
-    m_server.resolveJob(*m_currentJob, data);
+    m_server.resolveUnregistrationJob(*m_currentJob, m_registrationKey, unregistrationResult);
 
     finishCurrentJob();
 }
index c260c49..b9ba3be 100644 (file)
@@ -58,15 +58,18 @@ private:
     void jobTimerFired();
     void startNextJob();
     void rejectCurrentJob(const ExceptionData&);
-    void resolveCurrentJob(const ServiceWorkerRegistrationData&);
+    void resolveCurrentRegistrationJob(const ServiceWorkerRegistrationData&);
+    void resolveCurrentUnregistrationJob(bool unregistrationResult);
     void startScriptFetchForCurrentJob();
     void finishCurrentJob();
 
     void runRegisterJob(const ServiceWorkerJobData&);
+    void runUnregisterJob(const ServiceWorkerJobData&);
     void runUpdateJob(const ServiceWorkerJobData&);
 
     void rejectWithExceptionOnMainThread(const ExceptionData&);
     void resolveWithRegistrationOnMainThread();
+    void resolveWithUnregistrationResultOnMainThread(bool);
     void startScriptFetchFromMainThread();
     bool isEmpty();
     SWServerWorker* getNewestWorker();
index 9526b36..64c9014 100644 (file)
@@ -1,5 +1,21 @@
 2017-10-25  Chris Dumez  <cdumez@apple.com>
 
+        Add support for unregistering a service worker
+        https://bugs.webkit.org/show_bug.cgi?id=178735
+
+        Reviewed by Brady Eidson.
+
+        Add support for unregistering a service worker:
+        - https://w3c.github.io/ServiceWorker/#navigator-service-worker-unregister
+
+        * StorageProcess/ServiceWorker/WebSWServerConnection.cpp:
+        (WebKit::WebSWServerConnection::resolveRegistrationJobInClient):
+        (WebKit::WebSWServerConnection::resolveUnregistrationJobInClient):
+        * StorageProcess/ServiceWorker/WebSWServerConnection.h:
+        * WebProcess/Storage/WebSWClientConnection.messages.in:
+
+2017-10-25  Chris Dumez  <cdumez@apple.com>
+
         Make SharedStringHashTable less error prone
         https://bugs.webkit.org/show_bug.cgi?id=178764
 
index c4b6cea..e9bcb32 100644 (file)
@@ -75,11 +75,19 @@ void WebSWServerConnection::rejectJobInClient(uint64_t jobIdentifier, const Exce
     send(Messages::WebSWClientConnection::JobRejectedInServer(jobIdentifier, exceptionData));
 }
 
-void WebSWServerConnection::resolveJobInClient(uint64_t jobIdentifier, const ServiceWorkerRegistrationData& registrationData)
+void WebSWServerConnection::resolveRegistrationJobInClient(uint64_t jobIdentifier, const ServiceWorkerRegistrationData& registrationData)
 {
     auto origin = registrationData.key.topOrigin.securityOrigin();
     StorageProcess::singleton().ensureSWOriginStoreForSession(m_sessionID).add(origin);
-    send(Messages::WebSWClientConnection::JobResolvedInServer(jobIdentifier, registrationData));
+    send(Messages::WebSWClientConnection::RegistrationJobResolvedInServer(jobIdentifier, registrationData));
+}
+
+void WebSWServerConnection::resolveUnregistrationJobInClient(uint64_t jobIdentifier, const ServiceWorkerRegistrationKey& registrationKey, bool unregistrationResult)
+{
+    auto origin = registrationKey.topOrigin.securityOrigin();
+    if (auto* store = StorageProcess::singleton().swOriginStoreForSession(m_sessionID))
+        store->remove(origin);
+    send(Messages::WebSWClientConnection::UnregistrationJobResolvedInServer(jobIdentifier, unregistrationResult));
 }
 
 void WebSWServerConnection::startScriptFetchInClient(uint64_t jobIdentifier)
index 3a5720b..2926e83 100644 (file)
@@ -60,7 +60,8 @@ public:
 private:
     // Implement SWServer::Connection (Messages to the client WebProcess)
     void rejectJobInClient(uint64_t jobIdentifier, const WebCore::ExceptionData&) final;
-    void resolveJobInClient(uint64_t jobIdentifier, const WebCore::ServiceWorkerRegistrationData&) final;
+    void resolveRegistrationJobInClient(uint64_t jobIdentifier, const WebCore::ServiceWorkerRegistrationData&) final;
+    void resolveUnregistrationJobInClient(uint64_t jobIdentifier, const WebCore::ServiceWorkerRegistrationKey&, bool unregistrationResult) final;
     void startScriptFetchInClient(uint64_t jobIdentifier) final;
 
     void startFetch(uint64_t fetchIdentifier, uint64_t serviceWorkerIdentifier, const WebCore::ResourceRequest&, const WebCore::FetchOptions&);
index 88fea00..1155d1b 100644 (file)
@@ -25,7 +25,8 @@
 messages -> WebSWClientConnection {
     # When possible, these messages can be implemented directly by WebCore::SWServer::Connection
     JobRejectedInServer(uint64_t identifier, struct WebCore::ExceptionData exception)
-    JobResolvedInServer(uint64_t identifier, struct WebCore::ServiceWorkerRegistrationData registration)
+    RegistrationJobResolvedInServer(uint64_t identifier, struct WebCore::ServiceWorkerRegistrationData registration)
+    UnregistrationJobResolvedInServer(uint64_t identifier, bool unregistrationResult)
     StartScriptFetchForServer(uint64_t jobIdentifier)
 
     SetSWOriginTableSharedMemory(WebKit::SharedMemory::Handle handle)