Title: [224469] trunk
Revision
224469
Author
cdu...@apple.com
Date
2017-11-05 12:18:17 -0800 (Sun, 05 Nov 2017)

Log Message

Implement ServiceWorkerRegistration.update()
https://bugs.webkit.org/show_bug.cgi?id=179270

Reviewed by Youenn Fablet.

LayoutTests/imported/w3c:

Rebaseline WPT tests now that more are passing or at least failing later.

* web-platform-tests/service-workers/service-worker/claim-affect-other-registration.https-expected.txt:
* web-platform-tests/service-workers/service-worker/claim-with-redirect.https-expected.txt:
* web-platform-tests/service-workers/service-worker/import-scripts-redirect.https-expected.txt:
* web-platform-tests/service-workers/service-worker/multiple-register.https-expected.txt:
* web-platform-tests/service-workers/service-worker/multiple-update.https-expected.txt:
* web-platform-tests/service-workers/service-worker/postmessage-from-waiting-serviceworker.https-expected.txt:
* web-platform-tests/service-workers/service-worker/ready.https-expected.txt:
* web-platform-tests/service-workers/service-worker/registration-script.https-expected.txt:
* web-platform-tests/service-workers/service-worker/skip-waiting.https-expected.txt:
* web-platform-tests/service-workers/service-worker/unregister-then-register.https-expected.txt:

* web-platform-tests/service-workers/service-worker/update.https-expected.txt:
I investigated this test and it is still failing later on because we clear registrations too
aggressively on the StorageProcess side we are supposed to make sure the registration does
not have a newestWorker before clearing it when a script fetch fails or a script syntax error
occurs. We properly have those if (!newestWorker) checks in the code but service workers
are not yet populated on the SWServerRegistration object so SWServerRegistration::getNewestWorker()
alwasy returns null.

Source/WebCore:

Implement ServiceWorkerRegistration.update():
- https://w3c.github.io/ServiceWorker/#service-worker-registration-update

We already had support for the Update algorithm in SWServerJobQueue but
this patch enhances our support a bit to get us closer to the specification:
- https://w3c.github.io/ServiceWorker/#update-algorithm

No new tests, rebaselined existing tests.

* workers/service/ServiceWorker.h:
* workers/service/ServiceWorkerContainer.cpp:
(WebCore::ServiceWorkerContainer::updateRegistration):
(WebCore::ServiceWorkerContainer::getRegistration):
(WebCore::ServiceWorkerContainer::jobResolvedWithRegistration):
* workers/service/ServiceWorkerContainer.h:
* workers/service/ServiceWorkerJobData.h:
(WebCore::ServiceWorkerJobData::encode const):
(WebCore::ServiceWorkerJobData::decode):
* workers/service/ServiceWorkerJobType.h:
* workers/service/ServiceWorkerRegistration.cpp:
(WebCore::ServiceWorkerRegistration::ServiceWorkerRegistration):
(WebCore::ServiceWorkerRegistration::installing):
(WebCore::ServiceWorkerRegistration::waiting):
(WebCore::ServiceWorkerRegistration::active):
(WebCore::ServiceWorkerRegistration::setInstallingWorker):
(WebCore::ServiceWorkerRegistration::setWaitingWorker):
(WebCore::ServiceWorkerRegistration::setActiveWorker):
(WebCore::ServiceWorkerRegistration::getNewestWorker):
(WebCore::ServiceWorkerRegistration::update):
* workers/service/ServiceWorkerRegistration.h:
* workers/service/server/SWServerJobQueue.cpp:
(WebCore::SWServerJobQueue::scriptFetchFinished):
(WebCore::SWServerJobQueue::scriptContextFailedToStart):
(WebCore::SWServerJobQueue::runNextJobSynchronously):
(WebCore::SWServerJobQueue::runUpdateJob):

Modified Paths

Diff

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (224468 => 224469)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2017-11-05 19:20:53 UTC (rev 224468)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2017-11-05 20:18:17 UTC (rev 224469)
@@ -1,3 +1,31 @@
+2017-11-05  Chris Dumez  <cdu...@apple.com>
+
+        Implement ServiceWorkerRegistration.update()
+        https://bugs.webkit.org/show_bug.cgi?id=179270
+
+        Reviewed by Youenn Fablet.
+
+        Rebaseline WPT tests now that more are passing or at least failing later.
+
+        * web-platform-tests/service-workers/service-worker/claim-affect-other-registration.https-expected.txt:
+        * web-platform-tests/service-workers/service-worker/claim-with-redirect.https-expected.txt:
+        * web-platform-tests/service-workers/service-worker/import-scripts-redirect.https-expected.txt:
+        * web-platform-tests/service-workers/service-worker/multiple-register.https-expected.txt:
+        * web-platform-tests/service-workers/service-worker/multiple-update.https-expected.txt:
+        * web-platform-tests/service-workers/service-worker/postmessage-from-waiting-serviceworker.https-expected.txt:
+        * web-platform-tests/service-workers/service-worker/ready.https-expected.txt:
+        * web-platform-tests/service-workers/service-worker/registration-script.https-expected.txt:
+        * web-platform-tests/service-workers/service-worker/skip-waiting.https-expected.txt:
+        * web-platform-tests/service-workers/service-worker/unregister-then-register.https-expected.txt:
+
+        * web-platform-tests/service-workers/service-worker/update.https-expected.txt:
+        I investigated this test and it is still failing later on because we clear registrations too
+        aggressively on the StorageProcess side we are supposed to make sure the registration does
+        not have a newestWorker before clearing it when a script fetch fails or a script syntax error
+        occurs. We properly have those if (!newestWorker) checks in the code but service workers
+        are not yet populated on the SWServerRegistration object so SWServerRegistration::getNewestWorker()
+        alwasy returns null.
+
 2017-11-04  Chris Dumez  <cdu...@apple.com>
 
         Index properties on cross origin Window objects should be enumerable

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/claim-affect-other-registration.https-expected.txt (224468 => 224469)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/claim-affect-other-registration.https-expected.txt	2017-11-05 19:20:53 UTC (rev 224468)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/claim-affect-other-registration.https-expected.txt	2017-11-05 20:18:17 UTC (rev 224469)
@@ -1,4 +1,4 @@
 
 
-FAIL claim() should affect the originally controlling registration. assert_equals: Should be the same registration expected object "[object ServiceWorkerRegistration]" but got object "[object ServiceWorkerRegistration]"
+FAIL claim() should affect the originally controlling registration. promise_test: Unhandled rejection with value: object "NotSupportedError: Passing MessagePort objects to postMessage is not yet supported"
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/claim-with-redirect.https-expected.txt (224468 => 224469)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/claim-with-redirect.https-expected.txt	2017-11-05 19:20:53 UTC (rev 224468)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/claim-with-redirect.https-expected.txt	2017-11-05 20:18:17 UTC (rev 224469)
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: line 27: Unhandled Promise Rejection: NotSupportedError: ServiceWorkerRegistration::update not yet implemented
+CONSOLE MESSAGE: line 27: Unhandled Promise Rejection: InvalidStateError: newestWorker is null
   
 
 FAIL Claim works after redirection to another origin assert_equals: expected (string) "updated" but got (undefined) undefined

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/import-scripts-redirect.https-expected.txt (224468 => 224469)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/import-scripts-redirect.https-expected.txt	2017-11-05 19:20:53 UTC (rev 224468)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/import-scripts-redirect.https-expected.txt	2017-11-05 20:18:17 UTC (rev 224469)
@@ -1,4 +1,4 @@
 
 PASS importScripts() supports redirects 
-FAIL importScripts() supports redirects and can be updated promise_test: Unhandled rejection with value: object "NotSupportedError: ServiceWorkerRegistration::update not yet implemented"
+PASS importScripts() supports redirects and can be updated 
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/multiple-register.https-expected.txt (224468 => 224469)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/multiple-register.https-expected.txt	2017-11-05 19:20:53 UTC (rev 224468)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/multiple-register.https-expected.txt	2017-11-05 20:18:17 UTC (rev 224469)
@@ -1,6 +1,6 @@
 
 
-FAIL Subsequent registrations resolve to the same registration object assert_unreached: unexpected rejection: assert_equals: register should resolve to the same registration expected object "[object ServiceWorkerRegistration]" but got object "[object ServiceWorkerRegistration]" Reached unreachable code
+PASS Subsequent registrations resolve to the same registration object 
 FAIL Subsequent registrations from a different iframe resolve to the different registration object but they refer to the same registration and workers assert_unreached: unexpected rejection: assert_equals: installing worker should be null expected null but got object "[object ServiceWorker]" Reached unreachable code
-FAIL Concurrent registrations resolve to the same registration object assert_unreached: unexpected rejection: assert_equals: register should resolve to the same registration expected object "[object ServiceWorkerRegistration]" but got object "[object ServiceWorkerRegistration]" Reached unreachable code
+PASS Concurrent registrations resolve to the same registration object 
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/multiple-update.https-expected.txt (224468 => 224469)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/multiple-update.https-expected.txt	2017-11-05 19:20:53 UTC (rev 224468)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/multiple-update.https-expected.txt	2017-11-05 20:18:17 UTC (rev 224469)
@@ -1,3 +1,3 @@
 
-FAIL Trigger multiple updates. promise_test: Unhandled rejection with value: object "NotSupportedError: ServiceWorkerRegistration::update not yet implemented"
+PASS Trigger multiple updates. 
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/postmessage-from-waiting-serviceworker.https-expected.txt (224468 => 224469)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/postmessage-from-waiting-serviceworker.https-expected.txt	2017-11-05 19:20:53 UTC (rev 224468)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/postmessage-from-waiting-serviceworker.https-expected.txt	2017-11-05 20:18:17 UTC (rev 224469)
@@ -1,4 +1,4 @@
 
 
-FAIL Client.postMessage() from waiting serviceworker. assert_unreached: unexpected rejection: assert_equals: should be same registration expected object "[object ServiceWorkerRegistration]" but got object "[object ServiceWorkerRegistration]" Reached unreachable code
+FAIL Client.postMessage() from waiting serviceworker. assert_unreached: unexpected rejection: assert_equals: message event source should be correct expected null but got object "[object ServiceWorker]" Reached unreachable code
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/ready.https-expected.txt (224468 => 224469)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/ready.https-expected.txt	2017-11-05 19:20:53 UTC (rev 224468)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/ready.https-expected.txt	2017-11-05 20:18:17 UTC (rev 224469)
@@ -10,5 +10,5 @@
 FAIL ready on an iframe that installs a new service worker promise_test: Unhandled rejection with value: object "UnknownError: serviceWorker.ready() is not yet implemented"
 FAIL ready after a longer matched registration registered promise_test: Unhandled rejection with value: object "UnknownError: serviceWorker.ready() is not yet implemented"
 FAIL access ready after it has been resolved promise_test: Unhandled rejection with value: object "UnknownError: serviceWorker.ready() is not yet implemented"
-FAIL access ready on uninstalling registration that is resurrected assert_equals: existing registration should be resurrected expected object "[object ServiceWorkerRegistration]" but got object "[object ServiceWorkerRegistration]"
+FAIL access ready on uninstalling registration that is resurrected promise_test: Unhandled rejection with value: object "UnknownError: serviceWorker.ready() is not yet implemented"
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/registration-script.https-expected.txt (224468 => 224469)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/registration-script.https-expected.txt	2017-11-05 19:20:53 UTC (rev 224468)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/registration-script.https-expected.txt	2017-11-05 20:18:17 UTC (rev 224469)
@@ -1,6 +1,6 @@
 
-FAIL Registering invalid chunked encoding script assert_throws: Registration of invalid chunked encoding script should fail. function "function () { throw e }" threw object "UnknownError: Script URL https://localhost:9443/service-workers/service-worker/resources/invalid-chunked-encoding.py fetch resulted in error: cannot parse response" ("UnknownError") expected object "TypeError" ("TypeError")
-FAIL Registering invalid chunked encoding script with flush assert_throws: Registration of invalid chunked encoding script should fail. function "function () { throw e }" threw object "UnknownError: Script URL https://localhost:9443/service-workers/service-worker/resources/invalid-chunked-encoding-with-flush.py fetch resulted in error: cannot parse response" ("UnknownError") expected object "TypeError" ("TypeError")
+PASS Registering invalid chunked encoding script 
+PASS Registering invalid chunked encoding script with flush 
 FAIL Registering script including parse error assert_unreached: Should have rejected: Registration of script including parse error should fail. Reached unreachable code
 FAIL Registering script including undefined error assert_unreached: Should have rejected: Registration of script including undefined error should fail. Reached unreachable code
 FAIL Registering script including uncaught exception assert_unreached: Should have rejected: Registration of script including uncaught exception should fail. Reached unreachable code

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/skip-waiting.https-expected.txt (224468 => 224469)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/skip-waiting.https-expected.txt	2017-11-05 19:20:53 UTC (rev 224468)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/skip-waiting.https-expected.txt	2017-11-05 20:18:17 UTC (rev 224469)
@@ -1,3 +1,3 @@
 
-FAIL Test skipWaiting with both active and waiting workers promise_test: Unhandled rejection with value: object "TypeError: null is not an object (evaluating 'waiting_worker.scriptURL')"
+FAIL Test skipWaiting with both active and waiting workers assert_equals: Worker with url2 should be waiting expected "https://localhost:9443/service-workers/service-worker/resources/empty-worker.js" but got "https://localhost:9443/service-workers/service-worker/resources/empty.js"
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/unregister-then-register.https-expected.txt (224468 => 224469)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/unregister-then-register.https-expected.txt	2017-11-05 19:20:53 UTC (rev 224468)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/unregister-then-register.https-expected.txt	2017-11-05 20:18:17 UTC (rev 224469)
@@ -1,7 +1,7 @@
 
 
-PASS Unregister then register resolves to a new value 
-FAIL Unregister then register resolves to the original value if the registration is in use. assert_unreached: unexpected rejection: assert_equals: new registration should resolve to the same registration expected object "[object ServiceWorkerRegistration]" but got object "[object ServiceWorkerRegistration]" Reached unreachable code
+FAIL Unregister then register resolves to a new value assert_unreached: unexpected rejection: assert_not_equals: register should resolve to a new value got disallowed value object "[object ServiceWorkerRegistration]" Reached unreachable code
+PASS Unregister then register resolves to the original value if the registration is in use. 
 PASS Reloading the last controlled iframe after unregistration should ensure the deletion of the registration 
 FAIL Unregister then register does not affect existing controllee assert_unreached: unexpected rejection: assert_equals: installing version is null expected null but got object "[object ServiceWorker]" Reached unreachable code
 FAIL Unregister then register resurrects the registration assert_unreached: unexpected rejection: assert_not_equals: document should have a controller got disallowed value null Reached unreachable code

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/update.https-expected.txt (224468 => 224469)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/update.https-expected.txt	2017-11-05 19:20:53 UTC (rev 224468)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/update.https-expected.txt	2017-11-05 20:18:17 UTC (rev 224469)
@@ -1,3 +1,3 @@
 
-FAIL Update a registration. assert_throws: Using a disallowed mimetype should make update() promise reject with a SecurityError. function "function () { throw e; }" threw object "NotSupportedError: ServiceWorkerRegistration::update not yet implemented" that is not a DOMException SecurityError: property "code" is equal to 9, expected 18
+FAIL Update a registration. promise_test: Unhandled rejection with value: object "TypeError: Cannot update a null/nonexistent service worker registration"
 

Modified: trunk/Source/WebCore/ChangeLog (224468 => 224469)


--- trunk/Source/WebCore/ChangeLog	2017-11-05 19:20:53 UTC (rev 224468)
+++ trunk/Source/WebCore/ChangeLog	2017-11-05 20:18:17 UTC (rev 224469)
@@ -1,3 +1,46 @@
+2017-11-05  Chris Dumez  <cdu...@apple.com>
+
+        Implement ServiceWorkerRegistration.update()
+        https://bugs.webkit.org/show_bug.cgi?id=179270
+
+        Reviewed by Youenn Fablet.
+
+        Implement ServiceWorkerRegistration.update():
+        - https://w3c.github.io/ServiceWorker/#service-worker-registration-update
+
+        We already had support for the Update algorithm in SWServerJobQueue but
+        this patch enhances our support a bit to get us closer to the specification:
+        - https://w3c.github.io/ServiceWorker/#update-algorithm
+
+        No new tests, rebaselined existing tests.
+
+        * workers/service/ServiceWorker.h:
+        * workers/service/ServiceWorkerContainer.cpp:
+        (WebCore::ServiceWorkerContainer::updateRegistration):
+        (WebCore::ServiceWorkerContainer::getRegistration):
+        (WebCore::ServiceWorkerContainer::jobResolvedWithRegistration):
+        * workers/service/ServiceWorkerContainer.h:
+        * workers/service/ServiceWorkerJobData.h:
+        (WebCore::ServiceWorkerJobData::encode const):
+        (WebCore::ServiceWorkerJobData::decode):
+        * workers/service/ServiceWorkerJobType.h:
+        * workers/service/ServiceWorkerRegistration.cpp:
+        (WebCore::ServiceWorkerRegistration::ServiceWorkerRegistration):
+        (WebCore::ServiceWorkerRegistration::installing):
+        (WebCore::ServiceWorkerRegistration::waiting):
+        (WebCore::ServiceWorkerRegistration::active):
+        (WebCore::ServiceWorkerRegistration::setInstallingWorker):
+        (WebCore::ServiceWorkerRegistration::setWaitingWorker):
+        (WebCore::ServiceWorkerRegistration::setActiveWorker):
+        (WebCore::ServiceWorkerRegistration::getNewestWorker):
+        (WebCore::ServiceWorkerRegistration::update):
+        * workers/service/ServiceWorkerRegistration.h:
+        * workers/service/server/SWServerJobQueue.cpp:
+        (WebCore::SWServerJobQueue::scriptFetchFinished):
+        (WebCore::SWServerJobQueue::scriptContextFailedToStart):
+        (WebCore::SWServerJobQueue::runNextJobSynchronously):
+        (WebCore::SWServerJobQueue::runUpdateJob):
+
 2017-11-04  Simon Fraser  <simon.fra...@apple.com>
 
         Move code that maps a CompositeOperator and BlendMode to a CGBlendMode into a helper function

Modified: trunk/Source/WebCore/workers/service/ServiceWorker.h (224468 => 224469)


--- trunk/Source/WebCore/workers/service/ServiceWorker.h	2017-11-05 19:20:53 UTC (rev 224468)
+++ trunk/Source/WebCore/workers/service/ServiceWorker.h	2017-11-05 20:18:17 UTC (rev 224469)
@@ -59,7 +59,7 @@
         Redundant,
     };
 
-    const String& scriptURL() const { return m_scriptURL.string(); }
+    const URL& scriptURL() const { return m_scriptURL; }
 
     State state() const { return m_state; }
     void setState(State);

Modified: trunk/Source/WebCore/workers/service/ServiceWorkerContainer.cpp (224468 => 224469)


--- trunk/Source/WebCore/workers/service/ServiceWorkerContainer.cpp	2017-11-05 19:20:53 UTC (rev 224468)
+++ trunk/Source/WebCore/workers/service/ServiceWorkerContainer.cpp	2017-11-05 20:18:17 UTC (rev 224469)
@@ -165,6 +165,31 @@
     scheduleJob(ServiceWorkerJob::create(*this, WTFMove(promise), WTFMove(jobData)));
 }
 
+void ServiceWorkerContainer::updateRegistration(const URL& scopeURL, const URL& scriptURL, WorkerType, 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::Update;
+    jobData.scopeURL = scopeURL;
+    jobData.scriptURL = scriptURL;
+
+    scheduleJob(ServiceWorkerJob::create(*this, WTFMove(promise), WTFMove(jobData)));
+}
+
 void ServiceWorkerContainer::scheduleJob(Ref<ServiceWorkerJob>&& job)
 {
     ASSERT(m_swConnection);
@@ -206,8 +231,9 @@
         RefPtr<ServiceWorkerRegistration> registration = m_registrations.get(result->key);
         if (!registration) {
             auto& context = *scriptExecutionContext();
-            auto worker = ServiceWorker::create(context, *result->activeServiceWorkerIdentifier, result->scriptURL);
-            registration = ServiceWorkerRegistration::create(context, *this, WTFMove(result.value()), WTFMove(worker));
+            // FIXME: We should probably not be constructing ServiceWorkerRegistration objects here. Instead, we should make
+            // sure that ServiceWorkerRegistration objects stays alive as long as their SWServerRegistration on server side.
+            registration = ServiceWorkerRegistration::create(context, *this, WTFMove(result.value()));
         }
         promise->resolve<IDLInterface<ServiceWorkerRegistration>>(registration.releaseNonNull());
     });
@@ -251,9 +277,13 @@
         callOnMainThread([registration = WTFMove(m_registration)] () mutable {
             registration->dispatchEvent(Event::create(eventNames().updatefoundEvent, false, false));
             callOnMainThread([registration = WTFMove(registration)] () mutable {
-                registration->installing()->setState(ServiceWorker::State::Installed);
+                registration->setWaitingWorker(registration->installing());
+                registration->setInstallingWorker(nullptr);
+                registration->waiting()->setState(ServiceWorker::State::Installed);
                 callOnMainThread([registration = WTFMove(registration)] () mutable {
-                    registration->waiting()->setState(ServiceWorker::State::Activating);
+                    registration->setActiveWorker(registration->waiting());
+                    registration->setWaitingWorker(nullptr);
+                    registration->active()->setState(ServiceWorker::State::Activating);
                     callOnMainThread([registration = WTFMove(registration)] () mutable {
                         registration->active()->setState(ServiceWorker::State::Activated);
                     });
@@ -286,14 +316,17 @@
         activeServiceWorker = context->activeServiceWorker();
     }
 
+    RefPtr<ServiceWorkerRegistration> registration = m_registrations.get(data.key);
+    if (!registration)
+        registration = ServiceWorkerRegistration::create(*context, *this, WTFMove(data));
+
     activeServiceWorker->setState(ServiceWorker::State::Installing);
+    registration->setInstallingWorker(activeServiceWorker);
 
-    auto registration = ServiceWorkerRegistration::create(*context, *this, WTFMove(data), *activeServiceWorker);
+    job.promise().resolve<IDLInterface<ServiceWorkerRegistration>>(*registration);
 
-    job.promise().resolve<IDLInterface<ServiceWorkerRegistration>>(registration);
-
     // Use a microtask because we need to make sure this is executed after the promise above is resolved.
-    MicrotaskQueue::mainThreadQueue().append(std::make_unique<FakeServiceWorkerInstallMicrotask>(WTFMove(registration)));
+    MicrotaskQueue::mainThreadQueue().append(std::make_unique<FakeServiceWorkerInstallMicrotask>(registration.releaseNonNull()));
 }
 
 void ServiceWorkerContainer::jobResolvedWithUnregistrationResult(ServiceWorkerJob& job, bool unregistrationResult)
@@ -337,10 +370,13 @@
     m_swConnection->finishedFetchingScript(job, script);
 }
 
-void ServiceWorkerContainer::jobFailedLoadingScript(ServiceWorkerJob& job, const ResourceError& error)
+void ServiceWorkerContainer::jobFailedLoadingScript(ServiceWorkerJob& job, const ResourceError& error, std::optional<Exception>&& exception)
 {
     LOG(ServiceWorker, "SeviceWorkerContainer %p failed fetching script for job %" PRIu64, this, job.data().identifier());
 
+    if (exception)
+        job.promise().reject(*exception);
+
     m_swConnection->failedFetchingScript(job, error);
 }
 

Modified: trunk/Source/WebCore/workers/service/ServiceWorkerContainer.h (224468 => 224469)


--- trunk/Source/WebCore/workers/service/ServiceWorkerContainer.h	2017-11-05 19:20:53 UTC (rev 224468)
+++ trunk/Source/WebCore/workers/service/ServiceWorkerContainer.h	2017-11-05 20:18:17 UTC (rev 224469)
@@ -35,6 +35,7 @@
 #include "ServiceWorkerJobClient.h"
 #include "ServiceWorkerRegistration.h"
 #include "ServiceWorkerRegistrationOptions.h"
+#include "WorkerType.h"
 #include <pal/SessionID.h>
 #include <wtf/Threading.h>
 
@@ -61,6 +62,7 @@
 
     void addRegistration(const String& scriptURL, const RegistrationOptions&, Ref<DeferredPromise>&&);
     void removeRegistration(const URL& scopeURL, Ref<DeferredPromise>&&);
+    void updateRegistration(const URL& scopeURL, const URL& scriptURL, WorkerType, Ref<DeferredPromise>&&);
 
     void getRegistration(const String& clientURL, Ref<DeferredPromise>&&);
     void updateRegistration(const ServiceWorkerRegistrationKey&, ServiceWorkerRegistrationState, const std::optional<ServiceWorkerIdentifier>&);
@@ -84,7 +86,7 @@
     void jobResolvedWithUnregistrationResult(ServiceWorkerJob&, bool unregistrationResult) final;
     void startScriptFetchForJob(ServiceWorkerJob&) final;
     void jobFinishedLoadingScript(ServiceWorkerJob&, const String&) final;
-    void jobFailedLoadingScript(ServiceWorkerJob&, const ResourceError&) final;
+    void jobFailedLoadingScript(ServiceWorkerJob&, const ResourceError&, std::optional<Exception>&&) final;
 
     void jobDidFinish(ServiceWorkerJob&);
 

Modified: trunk/Source/WebCore/workers/service/ServiceWorkerJob.cpp (224468 => 224469)


--- trunk/Source/WebCore/workers/service/ServiceWorkerJob.cpp	2017-11-05 19:20:53 UTC (rev 224468)
+++ trunk/Source/WebCore/workers/service/ServiceWorkerJob.cpp	2017-11-05 20:18:17 UTC (rev 224469)
@@ -29,6 +29,7 @@
 #if ENABLE(SERVICE_WORKER)
 
 #include "JSDOMPromiseDeferred.h"
+#include "MIMETypeRegistry.h"
 #include "ResourceError.h"
 #include "ResourceResponse.h"
 #include "ServiceWorkerJobData.h"
@@ -100,6 +101,15 @@
     ASSERT(m_scriptLoader);
 
     m_lastResponse = response;
+    // Extract a MIME type from the response's header list. If this MIME type (ignoring parameters) is not a _javascript_ MIME type, then:
+    if (!MIMETypeRegistry::isSupportedJavaScriptMIMEType(response.mimeType())) {
+        // Invoke Reject Job Promise with job and "SecurityError" DOMException.
+        Exception exception { SecurityError, ASCIILiteral("MIME Type is not a _javascript_ MIME type") };
+        // Asynchronously complete these steps with a network error.
+        ResourceError error { errorDomainWebKitInternal, 0, response.url(), ASCIILiteral("Unexpected MIME type") };
+        m_client->jobFailedLoadingScript(*this, WTFMove(error), WTFMove(exception));
+        m_scriptLoader = nullptr;
+    }
 }
 
 void ServiceWorkerJob::notifyFinished()
@@ -110,7 +120,7 @@
     if (!m_scriptLoader->failed())
         m_client->jobFinishedLoadingScript(*this, m_scriptLoader->script());
     else
-        m_client->jobFailedLoadingScript(*this, m_scriptLoader->error());
+        m_client->jobFailedLoadingScript(*this, m_scriptLoader->error(), std::nullopt);
 
     m_scriptLoader = nullptr;
 }

Modified: trunk/Source/WebCore/workers/service/ServiceWorkerJobClient.h (224468 => 224469)


--- trunk/Source/WebCore/workers/service/ServiceWorkerJobClient.h	2017-11-05 19:20:53 UTC (rev 224468)
+++ trunk/Source/WebCore/workers/service/ServiceWorkerJobClient.h	2017-11-05 20:18:17 UTC (rev 224469)
@@ -44,7 +44,7 @@
     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;
+    virtual void jobFailedLoadingScript(ServiceWorkerJob&, const ResourceError&, std::optional<Exception>&&) = 0;
 
     virtual uint64_t connectionIdentifier() = 0;
 

Modified: trunk/Source/WebCore/workers/service/ServiceWorkerJobData.h (224468 => 224469)


--- trunk/Source/WebCore/workers/service/ServiceWorkerJobData.h	2017-11-05 19:20:53 UTC (rev 224468)
+++ trunk/Source/WebCore/workers/service/ServiceWorkerJobData.h	2017-11-05 20:18:17 UTC (rev 224469)
@@ -74,6 +74,7 @@
         encoder << registrationOptions;
         break;
     case ServiceWorkerJobType::Unregister:
+    case ServiceWorkerJobType::Update:
         break;
     }
 }
@@ -113,6 +114,7 @@
             return std::nullopt;
         break;
     case ServiceWorkerJobType::Unregister:
+    case ServiceWorkerJobType::Update:
         break;
     }
 

Modified: trunk/Source/WebCore/workers/service/ServiceWorkerJobType.h (224468 => 224469)


--- trunk/Source/WebCore/workers/service/ServiceWorkerJobType.h	2017-11-05 19:20:53 UTC (rev 224468)
+++ trunk/Source/WebCore/workers/service/ServiceWorkerJobType.h	2017-11-05 20:18:17 UTC (rev 224469)
@@ -32,6 +32,7 @@
 enum class ServiceWorkerJobType {
     Register,
     Unregister,
+    Update,
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/workers/service/ServiceWorkerRegistration.cpp (224468 => 224469)


--- trunk/Source/WebCore/workers/service/ServiceWorkerRegistration.cpp	2017-11-05 19:20:53 UTC (rev 224468)
+++ trunk/Source/WebCore/workers/service/ServiceWorkerRegistration.cpp	2017-11-05 20:18:17 UTC (rev 224469)
@@ -36,10 +36,9 @@
 
 namespace WebCore {
 
-ServiceWorkerRegistration::ServiceWorkerRegistration(ScriptExecutionContext& context, Ref<ServiceWorkerContainer>&& container, ServiceWorkerRegistrationData&& registrationData, Ref<ServiceWorker>&& serviceWorker)
+ServiceWorkerRegistration::ServiceWorkerRegistration(ScriptExecutionContext& context, Ref<ServiceWorkerContainer>&& container, ServiceWorkerRegistrationData&& registrationData)
     : ActiveDOMObject(&context)
     , m_registrationData(WTFMove(registrationData))
-    , m_serviceWorker(WTFMove(serviceWorker))
     , m_container(WTFMove(container))
 {
     suspendIfNeeded();
@@ -53,25 +52,44 @@
 
 ServiceWorker* ServiceWorkerRegistration::installing()
 {
-    if (m_serviceWorker->state() != ServiceWorker::State::Installing)
-        return nullptr;
-    return m_serviceWorker.ptr();
+    return m_installingWorker.get();
 }
 
 ServiceWorker* ServiceWorkerRegistration::waiting()
 {
-    if (m_serviceWorker->state() != ServiceWorker::State::Installed)
-        return nullptr;
-    return m_serviceWorker.ptr();
+    return m_waitingWorker.get();
 }
 
 ServiceWorker* ServiceWorkerRegistration::active()
 {
-    if (m_serviceWorker->state() != ServiceWorker::State::Activating && m_serviceWorker->state() != ServiceWorker::State::Activated)
-        return nullptr;
-    return m_serviceWorker.ptr();
+    return m_activeWorker.get();
 }
 
+void ServiceWorkerRegistration::setInstallingWorker(RefPtr<ServiceWorker>&& serviceWorker)
+{
+    m_installingWorker = WTFMove(serviceWorker);
+}
+
+void ServiceWorkerRegistration::setWaitingWorker(RefPtr<ServiceWorker>&& serviceWorker)
+{
+    m_waitingWorker = WTFMove(serviceWorker);
+}
+
+void ServiceWorkerRegistration::setActiveWorker(RefPtr<ServiceWorker>&& serviceWorker)
+{
+    m_activeWorker = WTFMove(serviceWorker);
+}
+
+ServiceWorker* ServiceWorkerRegistration::getNewestWorker()
+{
+    if (m_installingWorker)
+        return m_installingWorker.get();
+    if (m_waitingWorker)
+        return m_waitingWorker.get();
+
+    return m_activeWorker.get();
+}
+
 const String& ServiceWorkerRegistration::scope() const
 {
     return m_registrationData.scopeURL;
@@ -84,7 +102,27 @@
 
 void ServiceWorkerRegistration::update(Ref<DeferredPromise>&& promise)
 {
-    promise->reject(Exception(NotSupportedError, ASCIILiteral("ServiceWorkerRegistration::update not yet implemented")));
+    auto* context = scriptExecutionContext();
+    if (!context) {
+        ASSERT_NOT_REACHED();
+        promise->reject(Exception(InvalidStateError));
+        return;
+    }
+
+    auto* container = context->serviceWorkerContainer();
+    if (!container) {
+        promise->reject(Exception(InvalidStateError));
+        return;
+    }
+
+    auto* newestWorker = getNewestWorker();
+    if (!newestWorker) {
+        promise->reject(Exception(InvalidStateError, ASCIILiteral("newestWorker is null")));
+        return;
+    }
+
+    // FIXME: Support worker types.
+    container->updateRegistration(m_registrationData.scopeURL, newestWorker->scriptURL(), WorkerType::Classic, WTFMove(promise));
 }
 
 void ServiceWorkerRegistration::unregister(Ref<DeferredPromise>&& promise)

Modified: trunk/Source/WebCore/workers/service/ServiceWorkerRegistration.h (224468 => 224469)


--- trunk/Source/WebCore/workers/service/ServiceWorkerRegistration.h	2017-11-05 19:20:53 UTC (rev 224468)
+++ trunk/Source/WebCore/workers/service/ServiceWorkerRegistration.h	2017-11-05 20:18:17 UTC (rev 224469)
@@ -53,6 +53,12 @@
     ServiceWorker* waiting();
     ServiceWorker* active();
 
+    void setInstallingWorker(RefPtr<ServiceWorker>&&);
+    void setWaitingWorker(RefPtr<ServiceWorker>&&);
+    void setActiveWorker(RefPtr<ServiceWorker>&&);
+
+    ServiceWorker* getNewestWorker();
+
     const String& scope() const;
     ServiceWorkerUpdateViaCache updateViaCache() const;
 
@@ -67,7 +73,7 @@
     void updateStateFromServer(ServiceWorkerRegistrationState, std::optional<ServiceWorkerIdentifier>);
 
 private:
-    ServiceWorkerRegistration(ScriptExecutionContext&, Ref<ServiceWorkerContainer>&&, ServiceWorkerRegistrationData&&, Ref<ServiceWorker>&&);
+    ServiceWorkerRegistration(ScriptExecutionContext&, Ref<ServiceWorkerContainer>&&, ServiceWorkerRegistrationData&&);
 
     EventTargetInterface eventTargetInterface() const final;
     ScriptExecutionContext* scriptExecutionContext() const final;
@@ -78,8 +84,11 @@
     bool canSuspendForDocumentSuspension() const final;
 
     ServiceWorkerRegistrationData m_registrationData;
-    Ref<ServiceWorker> m_serviceWorker;
     Ref<ServiceWorkerContainer> m_container;
+
+    RefPtr<ServiceWorker> m_installingWorker;
+    RefPtr<ServiceWorker> m_waitingWorker;
+    RefPtr<ServiceWorker> m_activeWorker;
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/workers/service/server/SWServerJobQueue.cpp (224468 => 224469)


--- trunk/Source/WebCore/workers/service/server/SWServerJobQueue.cpp	2017-11-05 19:20:53 UTC (rev 224468)
+++ trunk/Source/WebCore/workers/service/server/SWServerJobQueue.cpp	2017-11-05 20:18:17 UTC (rev 224469)
@@ -58,19 +58,36 @@
     auto* registration = m_server.getRegistration(m_registrationKey);
     ASSERT(registration);
 
+    auto* newestWorker = registration->getNewestWorker();
+
     if (!result.scriptError.isNull()) {
-        rejectCurrentJob(ExceptionData { UnknownError, makeString("Script URL ", job.scriptURL.string(), " fetch resulted in error: ", result.scriptError.localizedDescription()) });
+        // Invoke Reject Job Promise with job and TypeError.
+        m_server.rejectJob(firstJob(), ExceptionData { TypeError, makeString("Script URL ", job.scriptURL.string(), " fetch resulted in error: ", result.scriptError.localizedDescription()) });
 
-        // If newestWorker is null, invoke Clear Registration algorithm passing this registration as its argument.
-        if (!registration->getNewestWorker())
+        // If newestWorker is null, invoke Clear Registration algorithm passing registration as its argument.
+        if (!newestWorker)
             clearRegistration(*registration);
 
+        // Invoke Finish Job with job and abort these steps.
+        finishCurrentJob();
         return;
     }
 
-    // FIXME: If the script data matches byte-for-byte with the existing newestWorker,
-    // then resolve and finish the job without doing anything further.
+    // If newestWorker is not null, newestWorker's script url equals job's script url with the exclude fragments
+    // flag set, and script's source text is a byte-for-byte match with newestWorker's script resource's source
+    // text, then:
+    if (newestWorker && equalIgnoringFragmentIdentifier(newestWorker->scriptURL(), job.scriptURL) && result.script == newestWorker->script()) {
+        // FIXME: if script is a classic script, and script's module record's [[ECMAScriptCode]] is a byte-for-byte
+        // match with newestWorker’s script resource's module record's [[ECMAScriptCode]] otherwise.
 
+        // Invoke Resolve Job Promise with job and registration.
+        m_server.resolveRegistrationJob(job, registration->data());
+
+        // Invoke Finish Job with job and abort these steps.
+        finishCurrentJob();
+        return;
+    }
+
     // FIXME: Support the proper worker type (classic vs module)
     m_server.updateWorker(connection, m_registrationKey, job.scriptURL, result.script, WorkerType::Classic);
 }
@@ -77,10 +94,16 @@
 
 void SWServerJobQueue::scriptContextFailedToStart(SWServer::Connection&, ServiceWorkerIdentifier identifier, const String& message)
 {
+    auto* registration = m_server.getRegistration(m_registrationKey);
+    ASSERT(registration);
+
     // FIXME: Install has failed. Run the install failed substeps
     // Run the Update Worker State algorithm passing registration’s installing worker and redundant as the arguments.
     // Run the Update Registration State algorithm passing registration, "installing" and null as the arguments.
+
     // If newestWorker is null, invoke Clear Registration algorithm passing registration as its argument.
+    if (!registration->getNewestWorker())
+        clearRegistration(*registration);
 
     UNUSED_PARAM(identifier);
     UNUSED_PARAM(message);
@@ -114,6 +137,9 @@
     case ServiceWorkerJobType::Unregister:
         runUnregisterJob(job);
         return;
+    case ServiceWorkerJobType::Update:
+        runUpdateJob(job);
+        return;
     }
 
     RELEASE_ASSERT_NOT_REACHED();
@@ -201,6 +227,7 @@
 // https://w3c.github.io/ServiceWorker/#update-algorithm
 void SWServerJobQueue::runUpdateJob(const ServiceWorkerJobData& job)
 {
+    // Let registration be the result of running the Get Registration algorithm passing job’s scope url as the argument.
     auto* registration = m_server.getRegistration(m_registrationKey);
 
     // If registration is null (in our parlance "empty") or registration’s uninstalling flag is set, then:
@@ -209,9 +236,11 @@
     if (registration->isUninstalling())
         return rejectCurrentJob(ExceptionData { TypeError, ASCIILiteral("Cannot update a service worker registration that is uninstalling") });
 
-    // If job's type is update, and newestWorker’s script url does not equal job’s script url with the exclude fragments flag set, then:
+    // Let newestWorker be the result of running Get Newest Worker algorithm passing registration as the argument.
     auto* newestWorker = registration->getNewestWorker();
-    if (newestWorker && !equalIgnoringFragmentIdentifier(job.scriptURL, newestWorker->scriptURL()))
+
+    // If job's type is update, and newestWorker's script url does not equal job’s script url with the exclude fragments flag set, then:
+    if (job.type == ServiceWorkerJobType::Update && newestWorker && !equalIgnoringFragmentIdentifier(job.scriptURL, newestWorker->scriptURL()))
         return rejectCurrentJob(ExceptionData { TypeError, ASCIILiteral("Cannot update a service worker with a requested script URL whose newest worker has a different script URL") });
 
     m_server.startScriptFetch(job);
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to