Title: [240727] trunk
Revision
240727
Author
[email protected]
Date
2019-01-30 13:00:30 -0800 (Wed, 30 Jan 2019)

Log Message

LayoutTests/imported/w3c:
ServiceWorkerJob should notify its client in case its job is cancelled
https://bugs.webkit.org/show_bug.cgi?id=193747
<rdar://problem/47498196>

Reviewed by Chris Dumez.

* web-platform-tests/service-workers/service-worker/registration-security-error.https-expected.txt:

Source/WebCore:
Refactor ServiceWorkerJob management by ServiceWorkerContainer to make it more memory safe
https://bugs.webkit.org/show_bug.cgi?id=193747
<rdar://problem/47498196>

Reviewed by Chris Dumez.

Make ServiceWorkerJob be no longer ref counted.
Instead its lifetime is fully controlled by ServiceWorkerContainer.

Make sure that a failing load will remove the job from ServiceWorkerContainer job map.
This allows to ensure that these jobs do not stay forever.
Before the patch, the jobs map was never cleared, which is creating a ref cycle whenever a job is not succesful.

Before the patch, unsetPendingActivity was only called for successful jobs finishing.
In case of failing loads, ServiceWorkerContainer would leak.
Make sure that setPendingActivity/unsetPendingActivity is balanced by storing
a pending activity in the job map next to the job.

When ServiceWorkerContainer is stopped, notify that all jobs are cancelled to NetworkProcess.
This makes these jobs in NetworkProcess-side to not stay until the corresponding WebProcess is gone.

Simplify ServiceWorkerJob promise rejection handling so that it is clear when promise is rejected and when it is not.
Update type of exception to be SecurityError when load fails due to AccessControl.

Covered by existing tests.

* workers/service/ServiceWorkerContainer.cpp:
(WebCore::ServiceWorkerContainer::addRegistration):
(WebCore::ServiceWorkerContainer::removeRegistration):
(WebCore::ServiceWorkerContainer::updateRegistration):
(WebCore::ServiceWorkerContainer::scheduleJob):
(WebCore::ServiceWorkerContainer::jobFailedWithException):
(WebCore::ServiceWorkerContainer::jobResolvedWithRegistration):
(WebCore::ServiceWorkerContainer::jobResolvedWithUnregistrationResult):
(WebCore::ServiceWorkerContainer::jobFailedLoadingScript):
(WebCore::ServiceWorkerContainer::jobDidFinish):
(WebCore::ServiceWorkerContainer::stop):
(WebCore::ServiceWorkerContainer::job):
* workers/service/ServiceWorkerContainer.h:
* workers/service/ServiceWorkerJob.cpp:
(WebCore::ServiceWorkerJob::failedWithException):
(WebCore::ServiceWorkerJob::resolvedWithRegistration):
(WebCore::ServiceWorkerJob::resolvedWithUnregistrationResult):
(WebCore::ServiceWorkerJob::startScriptFetch):
(WebCore::ServiceWorkerJob::didReceiveResponse):
(WebCore::ServiceWorkerJob::notifyFinished):
(WebCore::ServiceWorkerJob::cancelPendingLoad):
* workers/service/ServiceWorkerJob.h:
(WebCore::ServiceWorkerJob::hasPromise const):
(WebCore::ServiceWorkerJob::takePromise):
* workers/service/ServiceWorkerJobClient.h:
* workers/service/server/SWServerJobQueue.cpp:
(WebCore::SWServerJobQueue::scriptFetchFinished):

Modified Paths

Diff

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (240726 => 240727)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2019-01-30 20:27:45 UTC (rev 240726)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2019-01-30 21:00:30 UTC (rev 240727)
@@ -1,3 +1,13 @@
+2019-01-30  Youenn Fablet  <[email protected]>
+
+        ServiceWorkerJob should notify its client in case its job is cancelled
+        https://bugs.webkit.org/show_bug.cgi?id=193747
+        <rdar://problem/47498196>
+
+        Reviewed by Chris Dumez.
+
+        * web-platform-tests/service-workers/service-worker/registration-security-error.https-expected.txt:
+
 2019-01-29  Rob Buis  <[email protected]>
 
         Align with Fetch on data: URLs

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/registration-security-error.https-expected.txt (240726 => 240727)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/registration-security-error.https-expected.txt	2019-01-30 20:27:45 UTC (rev 240726)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/registration-security-error.https-expected.txt	2019-01-30 21:00:30 UTC (rev 240727)
@@ -3,7 +3,7 @@
 PASS Registration scope outside the script directory 
 PASS Registering scope outside domain 
 PASS Registering script outside domain 
-FAIL Registering redirected script assert_throws: Registration of redirected script should fail. function "function () { throw e }" threw object "TypeError: Script URL https://localhost:9443/service-workers/service-worker/resources/redirect.py?Redirect=%2Fresources%2Fregistration-worker.js fetch resulted in error: Not allowed to follow a redirection while loading https://localhost:9443/service-workers/service-worker/resources/redirect.py?Redirect=%2Fresources%2Fregistration-worker.js" that is not a DOMException SecurityError: property "code" is equal to undefined, expected 18
+PASS Registering redirected script 
 PASS Scope including parent-reference and not under the script directory 
 PASS Script URL including consecutive slashes 
 PASS Script URL is same-origin filesystem: URL 

Modified: trunk/Source/WebCore/ChangeLog (240726 => 240727)


--- trunk/Source/WebCore/ChangeLog	2019-01-30 20:27:45 UTC (rev 240726)
+++ trunk/Source/WebCore/ChangeLog	2019-01-30 21:00:30 UTC (rev 240727)
@@ -1,3 +1,59 @@
+2019-01-30  Youenn Fablet  <[email protected]>
+
+        Refactor ServiceWorkerJob management by ServiceWorkerContainer to make it more memory safe
+        https://bugs.webkit.org/show_bug.cgi?id=193747
+        <rdar://problem/47498196>
+
+        Reviewed by Chris Dumez.
+
+        Make ServiceWorkerJob be no longer ref counted.
+        Instead its lifetime is fully controlled by ServiceWorkerContainer.
+
+        Make sure that a failing load will remove the job from ServiceWorkerContainer job map.
+        This allows to ensure that these jobs do not stay forever.
+        Before the patch, the jobs map was never cleared, which is creating a ref cycle whenever a job is not succesful.
+
+        Before the patch, unsetPendingActivity was only called for successful jobs finishing.
+        In case of failing loads, ServiceWorkerContainer would leak.
+        Make sure that setPendingActivity/unsetPendingActivity is balanced by storing
+        a pending activity in the job map next to the job.
+
+        When ServiceWorkerContainer is stopped, notify that all jobs are cancelled to NetworkProcess.
+        This makes these jobs in NetworkProcess-side to not stay until the corresponding WebProcess is gone.
+
+        Simplify ServiceWorkerJob promise rejection handling so that it is clear when promise is rejected and when it is not.
+        Update type of exception to be SecurityError when load fails due to AccessControl.
+
+        Covered by existing tests.
+
+        * workers/service/ServiceWorkerContainer.cpp:
+        (WebCore::ServiceWorkerContainer::addRegistration):
+        (WebCore::ServiceWorkerContainer::removeRegistration):
+        (WebCore::ServiceWorkerContainer::updateRegistration):
+        (WebCore::ServiceWorkerContainer::scheduleJob):
+        (WebCore::ServiceWorkerContainer::jobFailedWithException):
+        (WebCore::ServiceWorkerContainer::jobResolvedWithRegistration):
+        (WebCore::ServiceWorkerContainer::jobResolvedWithUnregistrationResult):
+        (WebCore::ServiceWorkerContainer::jobFailedLoadingScript):
+        (WebCore::ServiceWorkerContainer::jobDidFinish):
+        (WebCore::ServiceWorkerContainer::stop):
+        (WebCore::ServiceWorkerContainer::job):
+        * workers/service/ServiceWorkerContainer.h:
+        * workers/service/ServiceWorkerJob.cpp:
+        (WebCore::ServiceWorkerJob::failedWithException):
+        (WebCore::ServiceWorkerJob::resolvedWithRegistration):
+        (WebCore::ServiceWorkerJob::resolvedWithUnregistrationResult):
+        (WebCore::ServiceWorkerJob::startScriptFetch):
+        (WebCore::ServiceWorkerJob::didReceiveResponse):
+        (WebCore::ServiceWorkerJob::notifyFinished):
+        (WebCore::ServiceWorkerJob::cancelPendingLoad):
+        * workers/service/ServiceWorkerJob.h:
+        (WebCore::ServiceWorkerJob::hasPromise const):
+        (WebCore::ServiceWorkerJob::takePromise):
+        * workers/service/ServiceWorkerJobClient.h:
+        * workers/service/server/SWServerJobQueue.cpp:
+        (WebCore::SWServerJobQueue::scriptFetchFinished):
+
 2019-01-30  Dean Jackson  <[email protected]>
 
         PointerEvents - tiltX and tiltY are reversed

Modified: trunk/Source/WebCore/workers/service/ServiceWorkerContainer.cpp (240726 => 240727)


--- trunk/Source/WebCore/workers/service/ServiceWorkerContainer.cpp	2019-01-30 20:27:45 UTC (rev 240726)
+++ trunk/Source/WebCore/workers/service/ServiceWorkerContainer.cpp	2019-01-30 21:00:30 UTC (rev 240727)
@@ -176,7 +176,7 @@
     jobData.type = ServiceWorkerJobType::Register;
     jobData.registrationOptions = options;
 
-    scheduleJob(ServiceWorkerJob::create(*this, WTFMove(promise), WTFMove(jobData)));
+    scheduleJob(std::make_unique<ServiceWorkerJob>(*this, WTFMove(promise), WTFMove(jobData)));
 }
 
 void ServiceWorkerContainer::removeRegistration(const URL& scopeURL, Ref<DeferredPromise>&& promise)
@@ -202,7 +202,7 @@
 
     CONTAINER_RELEASE_LOG_IF_ALLOWED("removeRegistration: Unregistering service worker. Job ID: %" PRIu64, jobData.identifier().jobIdentifier.toUInt64());
 
-    scheduleJob(ServiceWorkerJob::create(*this, WTFMove(promise), WTFMove(jobData)));
+    scheduleJob(std::make_unique<ServiceWorkerJob>(*this, WTFMove(promise), WTFMove(jobData)));
 }
 
 void ServiceWorkerContainer::updateRegistration(const URL& scopeURL, const URL& scriptURL, WorkerType, RefPtr<DeferredPromise>&& promise)
@@ -228,10 +228,10 @@
 
     CONTAINER_RELEASE_LOG_IF_ALLOWED("removeRegistration: Updating service worker. Job ID: %" PRIu64, jobData.identifier().jobIdentifier.toUInt64());
 
-    scheduleJob(ServiceWorkerJob::create(*this, WTFMove(promise), WTFMove(jobData)));
+    scheduleJob(std::make_unique<ServiceWorkerJob>(*this, WTFMove(promise), WTFMove(jobData)));
 }
 
-void ServiceWorkerContainer::scheduleJob(Ref<ServiceWorkerJob>&& job)
+void ServiceWorkerContainer::scheduleJob(std::unique_ptr<ServiceWorkerJob>&& job)
 {
 #ifndef NDEBUG
     ASSERT(m_creationThread.ptr() == &Thread::current());
@@ -238,12 +238,12 @@
 #endif
 
     ASSERT(m_swConnection);
+    ASSERT(!isStopped());
 
-    setPendingActivity(*this);
-
     auto& jobData = job->data();
-    auto result = m_jobMap.add(job->identifier(), WTFMove(job));
-    ASSERT_UNUSED(result, result.isNewEntry);
+    auto jobIdentifier = job->identifier();
+    ASSERT(!m_jobMap.contains(jobIdentifier));
+    m_jobMap.add(jobIdentifier, OngoingJob { WTFMove(job), makePendingActivity(*this) });
 
     callOnMainThread([connection = m_swConnection, contextIdentifier = this->contextIdentifier(), jobData = jobData.isolatedCopy()] {
         connection->scheduleJob(contextIdentifier, jobData);
@@ -385,20 +385,21 @@
     ASSERT(m_creationThread.ptr() == &Thread::current());
 #endif
 
-    ASSERT_WITH_MESSAGE(job.promise() || job.data().type == ServiceWorkerJobType::Update, "Only soft updates have no promise");
+    ASSERT_WITH_MESSAGE(job.hasPromise() || job.data().type == ServiceWorkerJobType::Update, "Only soft updates have no promise");
 
     auto guard = WTF::makeScopeExit([this, &job] {
-        jobDidFinish(job);
+        destroyJob(job);
     });
 
     CONTAINER_RELEASE_LOG_ERROR_IF_ALLOWED("jobFailedWithException: Job %" PRIu64 " failed with error %s", job.identifier().toUInt64(), exception.message().utf8().data());
 
-    if (!job.promise())
+    auto promise = job.takePromise();
+    if (!promise)
         return;
 
     if (auto* context = scriptExecutionContext()) {
-        context->postTask([job = makeRef(job), exception](ScriptExecutionContext&) {
-            job->promise()->reject(exception);
+        context->postTask([promise = WTFMove(promise), exception](auto&) mutable {
+            promise->reject(exception);
         });
     }
 }
@@ -418,10 +419,10 @@
 #ifndef NDEBUG
     ASSERT(m_creationThread.ptr() == &Thread::current());
 #endif
-    ASSERT_WITH_MESSAGE(job.promise() || job.data().type == ServiceWorkerJobType::Update, "Only soft updates have no promise");
+    ASSERT_WITH_MESSAGE(job.hasPromise() || job.data().type == ServiceWorkerJobType::Update, "Only soft updates have no promise");
 
     auto guard = WTF::makeScopeExit([this, &job] {
-        jobDidFinish(job);
+        destroyJob(job);
     });
 
     if (job.data().type == ServiceWorkerJobType::Register)
@@ -446,13 +447,14 @@
         return;
     }
 
-    if (!job.promise()) {
+    auto promise = job.takePromise();
+    if (!promise) {
         if (notifyWhenResolvedIfNeeded)
             notifyWhenResolvedIfNeeded();
         return;
     }
 
-    scriptExecutionContext()->postTask([this, protectedThis = makeRef(*this), job = makeRef(job), data = "" notifyWhenResolvedIfNeeded = WTFMove(notifyWhenResolvedIfNeeded)](ScriptExecutionContext& context) mutable {
+    scriptExecutionContext()->postTask([this, protectedThis = makeRef(*this), promise = WTFMove(promise), jobIdentifier = job.identifier(), data = "" notifyWhenResolvedIfNeeded = WTFMove(notifyWhenResolvedIfNeeded)](ScriptExecutionContext& context) mutable {
         if (isStopped() || !context.sessionID().isValid()) {
             if (notifyWhenResolvedIfNeeded)
                 notifyWhenResolvedIfNeeded();
@@ -461,15 +463,15 @@
 
         auto registration = ServiceWorkerRegistration::getOrCreate(context, *this, WTFMove(data));
 
-        CONTAINER_RELEASE_LOG_IF_ALLOWED("jobResolvedWithRegistration: Resolving promise for job %" PRIu64 ". Registration ID: %" PRIu64, job->identifier().toUInt64(), registration->identifier().toUInt64());
+        CONTAINER_RELEASE_LOG_IF_ALLOWED("jobResolvedWithRegistration: Resolving promise for job %" PRIu64 ". Registration ID: %" PRIu64, jobIdentifier.toUInt64(), registration->identifier().toUInt64());
 
         if (notifyWhenResolvedIfNeeded) {
-            job->promise()->whenSettled([notifyWhenResolvedIfNeeded = WTFMove(notifyWhenResolvedIfNeeded)] {
+            promise->whenSettled([notifyWhenResolvedIfNeeded = WTFMove(notifyWhenResolvedIfNeeded)] {
                 notifyWhenResolvedIfNeeded();
             });
         }
 
-        job->promise()->resolve<IDLInterface<ServiceWorkerRegistration>>(WTFMove(registration));
+        promise->resolve<IDLInterface<ServiceWorkerRegistration>>(WTFMove(registration));
     });
 }
 
@@ -479,10 +481,10 @@
     ASSERT(m_creationThread.ptr() == &Thread::current());
 #endif
 
-    ASSERT(job.promise());
+    ASSERT(job.hasPromise());
 
     auto guard = WTF::makeScopeExit([this, &job] {
-        jobDidFinish(job);
+        destroyJob(job);
     });
 
     CONTAINER_RELEASE_LOG_IF_ALLOWED("jobResolvedWithUnregistrationResult: Unregister job %" PRIu64 " finished. Success? %d", job.identifier().toUInt64(), unregistrationResult);
@@ -493,8 +495,8 @@
         return;
     }
 
-    context->postTask([job = makeRef(job), unregistrationResult](ScriptExecutionContext&) mutable {
-        job->promise()->resolve<IDLBoolean>(unregistrationResult);
+    context->postTask([promise = job.takePromise(), unregistrationResult](auto&) mutable {
+        promise->resolve<IDLBoolean>(unregistrationResult);
     });
 }
 
@@ -509,10 +511,8 @@
     auto* context = scriptExecutionContext();
     if (!context) {
         LOG_ERROR("ServiceWorkerContainer::jobResolvedWithRegistration called but the container's ScriptExecutionContext is gone");
-        callOnMainThread([connection = m_swConnection, jobIdentifier = job.identifier(), registrationKey = job.data().registrationKey().isolatedCopy(), scriptURL = job.data().scriptURL.isolatedCopy()] {
-            connection->failedFetchingScript(jobIdentifier, registrationKey, { errorDomainWebKitInternal, 0, scriptURL, "Attempt to fetch service worker script with no ScriptExecutionContext"_s });
-        });
-        jobDidFinish(job);
+        notifyFailedFetchingScript(job, { errorDomainWebKitInternal, 0, job.data().scriptURL, "Attempt to fetch service worker script with no ScriptExecutionContext"_s });
+        destroyJob(job);
         return;
     }
 
@@ -532,33 +532,37 @@
     });
 }
 
-void ServiceWorkerContainer::jobFailedLoadingScript(ServiceWorkerJob& job, const ResourceError& error, Optional<Exception>&& exception)
+void ServiceWorkerContainer::jobFailedLoadingScript(ServiceWorkerJob& job, const ResourceError& error, Exception&& exception)
 {
 #ifndef NDEBUG
     ASSERT(m_creationThread.ptr() == &Thread::current());
 #endif
-    ASSERT_WITH_MESSAGE(job.promise() || job.data().type == ServiceWorkerJobType::Update, "Only soft updates have no promise");
+    ASSERT_WITH_MESSAGE(job.hasPromise() || job.data().type == ServiceWorkerJobType::Update, "Only soft updates have no promise");
 
     CONTAINER_RELEASE_LOG_ERROR_IF_ALLOWED("jobFinishedLoadingScript: Failed to fetch script for job %" PRIu64 ", error: %s", job.identifier().toUInt64(), error.localizedDescription().utf8().data());
 
-    if (exception && job.promise())
-        job.promise()->reject(*exception);
+    if (auto promise = job.takePromise())
+        promise->reject(WTFMove(exception));
 
+    notifyFailedFetchingScript(job, error);
+    destroyJob(job);
+}
+
+void ServiceWorkerContainer::notifyFailedFetchingScript(ServiceWorkerJob& job, const ResourceError& error)
+{
     callOnMainThread([connection = m_swConnection, jobIdentifier = job.identifier(), registrationKey = job.data().registrationKey().isolatedCopy(), error = error.isolatedCopy()] {
         connection->failedFetchingScript(jobIdentifier, registrationKey, error);
     });
 }
 
-void ServiceWorkerContainer::jobDidFinish(ServiceWorkerJob& job)
+void ServiceWorkerContainer::destroyJob(ServiceWorkerJob& job)
 {
 #ifndef NDEBUG
     ASSERT(m_creationThread.ptr() == &Thread::current());
 #endif
 
-    auto taken = m_jobMap.take(job.identifier());
-    ASSERT_UNUSED(taken, !taken || taken->ptr() == &job);
-
-    unsetPendingActivity(*this);
+    ASSERT(m_jobMap.contains(job.identifier()));
+    m_jobMap.remove(job.identifier());
 }
 
 SWServerConnectionIdentifier ServiceWorkerContainer::connectionIdentifier()
@@ -633,8 +637,11 @@
     removeAllEventListeners();
     m_pendingPromises.clear();
     m_readyPromise = nullptr;
-    for (auto& job : m_jobMap.values())
-        job->cancelPendingLoad();
+    auto jobMap = WTFMove(m_jobMap);
+    for (auto& ongoingJob : jobMap.values()) {
+        notifyFailedFetchingScript(*ongoingJob.job.get(), ResourceError { errorDomainWebKitInternal, 0, ongoingJob.job->data().scriptURL, "Job cancelled"_s, ResourceError::Type::Cancellation });
+        ongoingJob.job->cancelPendingLoad();
+    }
 }
 
 DocumentOrWorkerIdentifier ServiceWorkerContainer::contextIdentifier()
@@ -649,6 +656,14 @@
     return downcast<Document>(*scriptExecutionContext()).identifier();
 }
 
+ServiceWorkerJob* ServiceWorkerContainer::job(ServiceWorkerJobIdentifier identifier)
+{
+    auto iterator = m_jobMap.find(identifier);
+    if (iterator == m_jobMap.end())
+        return nullptr;
+    return iterator->value.job.get();
+}
+
 bool ServiceWorkerContainer::isAlwaysOnLoggingAllowed() const
 {
     auto* context = scriptExecutionContext();

Modified: trunk/Source/WebCore/workers/service/ServiceWorkerContainer.h (240726 => 240727)


--- trunk/Source/WebCore/workers/service/ServiceWorkerContainer.h	2019-01-30 20:27:45 UTC (rev 240726)
+++ trunk/Source/WebCore/workers/service/ServiceWorkerContainer.h	2019-01-30 21:00:30 UTC (rev 240727)
@@ -77,19 +77,16 @@
     void addRegistration(ServiceWorkerRegistration&);
     void removeRegistration(ServiceWorkerRegistration&);
 
-    ServiceWorkerJob* job(ServiceWorkerJobIdentifier identifier) { return m_jobMap.get(identifier); }
+    ServiceWorkerJob* job(ServiceWorkerJobIdentifier);
 
     void startMessages();
 
-    void ref() final { refEventTarget(); }
-    void deref() final { derefEventTarget(); }
-
     bool isStopped() const { return m_isStopped; };
 
     bool isAlwaysOnLoggingAllowed() const;
 
 private:
-    void scheduleJob(Ref<ServiceWorkerJob>&&);
+    void scheduleJob(std::unique_ptr<ServiceWorkerJob>&&);
 
     void jobFailedWithException(ServiceWorkerJob&, const Exception&) final;
     void jobResolvedWithRegistration(ServiceWorkerJob&, ServiceWorkerRegistrationData&&, ShouldNotifyWhenResolved) final;
@@ -96,9 +93,10 @@
     void jobResolvedWithUnregistrationResult(ServiceWorkerJob&, bool unregistrationResult) final;
     void startScriptFetchForJob(ServiceWorkerJob&, FetchOptions::Cache) final;
     void jobFinishedLoadingScript(ServiceWorkerJob&, const String& script, const ContentSecurityPolicyResponseHeaders&, const String& referrerPolicy) final;
-    void jobFailedLoadingScript(ServiceWorkerJob&, const ResourceError&, Optional<Exception>&&) final;
+    void jobFailedLoadingScript(ServiceWorkerJob&, const ResourceError&, Exception&&) final;
 
-    void jobDidFinish(ServiceWorkerJob&);
+    void notifyFailedFetchingScript(ServiceWorkerJob&, const ResourceError&);
+    void destroyJob(ServiceWorkerJob&);
 
     void didFinishGetRegistrationRequest(uint64_t requestIdentifier, Optional<ServiceWorkerRegistrationData>&&);
     void didFinishGetRegistrationsRequest(uint64_t requestIdentifier, Vector<ServiceWorkerRegistrationData>&&);
@@ -121,8 +119,13 @@
     NavigatorBase& m_navigator;
 
     RefPtr<SWClientConnection> m_swConnection;
-    HashMap<ServiceWorkerJobIdentifier, Ref<ServiceWorkerJob>> m_jobMap;
 
+    struct OngoingJob {
+        std::unique_ptr<ServiceWorkerJob> job;
+        RefPtr<PendingActivity<ServiceWorkerContainer>> pendingActivity;
+    };
+    HashMap<ServiceWorkerJobIdentifier, OngoingJob> m_jobMap;
+
     bool m_isStopped { false };
     HashMap<ServiceWorkerRegistrationIdentifier, ServiceWorkerRegistration*> m_registrations;
 

Modified: trunk/Source/WebCore/workers/service/ServiceWorkerJob.cpp (240726 => 240727)


--- trunk/Source/WebCore/workers/service/ServiceWorkerJob.cpp	2019-01-30 20:27:45 UTC (rev 240726)
+++ trunk/Source/WebCore/workers/service/ServiceWorkerJob.cpp	2019-01-30 21:00:30 UTC (rev 240727)
@@ -57,7 +57,7 @@
     ASSERT(!m_completed);
 
     m_completed = true;
-    m_client->jobFailedWithException(*this, exception);
+    m_client.jobFailedWithException(*this, exception);
 }
 
 void ServiceWorkerJob::resolvedWithRegistration(ServiceWorkerRegistrationData&& data, ShouldNotifyWhenResolved shouldNotifyWhenResolved)
@@ -66,7 +66,7 @@
     ASSERT(!m_completed);
 
     m_completed = true;
-    m_client->jobResolvedWithRegistration(*this, WTFMove(data), shouldNotifyWhenResolved);
+    m_client.jobResolvedWithRegistration(*this, WTFMove(data), shouldNotifyWhenResolved);
 }
 
 void ServiceWorkerJob::resolvedWithUnregistrationResult(bool unregistrationResult)
@@ -75,7 +75,7 @@
     ASSERT(!m_completed);
 
     m_completed = true;
-    m_client->jobResolvedWithUnregistrationResult(*this, unregistrationResult);
+    m_client.jobResolvedWithUnregistrationResult(*this, unregistrationResult);
 }
 
 void ServiceWorkerJob::startScriptFetch(FetchOptions::Cache cachePolicy)
@@ -83,7 +83,7 @@
     ASSERT(m_creationThread.ptr() == &Thread::current());
     ASSERT(!m_completed);
 
-    m_client->startScriptFetchForJob(*this, cachePolicy);
+    m_client.startScriptFetchForJob(*this, cachePolicy);
 }
 
 void ServiceWorkerJob::fetchScriptWithContext(ScriptExecutionContext& context, FetchOptions::Cache cachePolicy)
@@ -114,13 +114,17 @@
 
     // 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())) {
+        m_scriptLoader->cancel();
+        m_scriptLoader = nullptr;
+
         // Invoke Reject Job Promise with job and "SecurityError" DOMException.
         Exception exception { SecurityError, "MIME Type is not a _javascript_ MIME type"_s };
         // Asynchronously complete these steps with a network error.
         ResourceError error { errorDomainWebKitInternal, 0, response.url(), "Unexpected MIME type"_s };
-        m_client->jobFailedLoadingScript(*this, WTFMove(error), WTFMove(exception));
-        m_scriptLoader = nullptr;
+        m_client.jobFailedLoadingScript(*this, WTFMove(error), WTFMove(exception));
+        return;
     }
+
     String serviceWorkerAllowed = response.httpHeaderField(HTTPHeaderName::ServiceWorkerAllowed);
     String maxScopeString;
     if (serviceWorkerAllowed.isNull()) {
@@ -131,13 +135,17 @@
         auto maxScope = URL(m_jobData.scriptURL, serviceWorkerAllowed);
         maxScopeString = maxScope.path();
     }
+
     String scopeString = m_jobData.scopeURL.path();
-    if (!scopeString.startsWith(maxScopeString)) {
-        Exception exception { SecurityError, "Scope URL should start with the given script URL"_s };
-        ResourceError error { errorDomainWebKitInternal, 0, response.url(), "Scope URL should start with the given script URL"_s };
-        m_client->jobFailedLoadingScript(*this, WTFMove(error), WTFMove(exception));
-        m_scriptLoader = nullptr;
-    }
+    if (scopeString.startsWith(maxScopeString))
+        return;
+
+    m_scriptLoader->cancel();
+    m_scriptLoader = nullptr;
+
+    Exception exception { SecurityError, "Scope URL should start with the given script URL"_s };
+    ResourceError error { errorDomainWebKitInternal, 0, response.url(), "Scope URL should start with the given script URL"_s };
+    m_client.jobFailedLoadingScript(*this, WTFMove(error), WTFMove(exception));
 }
 
 void ServiceWorkerJob::notifyFinished()
@@ -145,15 +153,17 @@
     ASSERT(m_creationThread.ptr() == &Thread::current());
     ASSERT(m_scriptLoader);
     
-    if (!m_scriptLoader->failed())
-        m_client->jobFinishedLoadingScript(*this, m_scriptLoader->script(), m_scriptLoader->contentSecurityPolicy(), m_scriptLoader->referrerPolicy());
-    else {
-        auto& error =  m_scriptLoader->error();
-        ASSERT(!error.isNull());
-        m_client->jobFailedLoadingScript(*this, error, WTF::nullopt);
+    auto scriptLoader = WTFMove(m_scriptLoader);
+
+    if (!scriptLoader->failed()) {
+        m_client.jobFinishedLoadingScript(*this, scriptLoader->script(), scriptLoader->contentSecurityPolicy(), scriptLoader->referrerPolicy());
+        return;
     }
 
-    m_scriptLoader = nullptr;
+    auto& error = scriptLoader->error();
+    ASSERT(!error.isNull());
+
+    m_client.jobFailedLoadingScript(*this, error, Exception { error.isAccessControl() ? SecurityError : TypeError, "Script load failed"_s });
 }
 
 void ServiceWorkerJob::cancelPendingLoad()

Modified: trunk/Source/WebCore/workers/service/ServiceWorkerJob.h (240726 => 240727)


--- trunk/Source/WebCore/workers/service/ServiceWorkerJob.h	2019-01-30 20:27:45 UTC (rev 240726)
+++ trunk/Source/WebCore/workers/service/ServiceWorkerJob.h	2019-01-30 21:00:30 UTC (rev 240727)
@@ -27,6 +27,7 @@
 
 #if ENABLE(SERVICE_WORKER)
 
+#include "JSDOMPromiseDeferred.h"
 #include "ResourceResponse.h"
 #include "ServiceWorkerJobClient.h"
 #include "ServiceWorkerJobData.h"
@@ -46,13 +47,10 @@
 enum class ServiceWorkerJobType;
 struct ServiceWorkerRegistrationData;
 
-class ServiceWorkerJob : public ThreadSafeRefCounted<ServiceWorkerJob>, public WorkerScriptLoaderClient {
+class ServiceWorkerJob : public WorkerScriptLoaderClient {
+    WTF_MAKE_FAST_ALLOCATED;
 public:
-    static Ref<ServiceWorkerJob> create(ServiceWorkerJobClient& client, RefPtr<DeferredPromise>&& promise, ServiceWorkerJobData&& jobData)
-    {
-        return adoptRef(*new ServiceWorkerJob(client, WTFMove(promise), WTFMove(jobData)));
-    }
-
+    ServiceWorkerJob(ServiceWorkerJobClient&, RefPtr<DeferredPromise>&&, ServiceWorkerJobData&&);
     WEBCORE_EXPORT ~ServiceWorkerJob();
 
     void failedWithException(const Exception&);
@@ -64,7 +62,8 @@
     Identifier identifier() const { return m_jobData.identifier().jobIdentifier; }
 
     const ServiceWorkerJobData& data() const { return m_jobData; }
-    DeferredPromise* promise() { return m_promise.get(); }
+    bool hasPromise() const { return !!m_promise; }
+    RefPtr<DeferredPromise> takePromise() { return WTFMove(m_promise); }
 
     void fetchScriptWithContext(ScriptExecutionContext&, FetchOptions::Cache);
 
@@ -73,13 +72,11 @@
     void cancelPendingLoad();
 
 private:
-    ServiceWorkerJob(ServiceWorkerJobClient&, RefPtr<DeferredPromise>&&, ServiceWorkerJobData&&);
-
     // WorkerScriptLoaderClient
     void didReceiveResponse(unsigned long identifier, const ResourceResponse&) final;
     void notifyFinished() final;
 
-    Ref<ServiceWorkerJobClient> m_client;
+    ServiceWorkerJobClient& m_client;
     ServiceWorkerJobData m_jobData;
     RefPtr<DeferredPromise> m_promise;
 

Modified: trunk/Source/WebCore/workers/service/ServiceWorkerJobClient.h (240726 => 240727)


--- trunk/Source/WebCore/workers/service/ServiceWorkerJobClient.h	2019-01-30 20:27:45 UTC (rev 240726)
+++ trunk/Source/WebCore/workers/service/ServiceWorkerJobClient.h	2019-01-30 21:00:30 UTC (rev 240727)
@@ -50,12 +50,9 @@
     virtual void jobResolvedWithUnregistrationResult(ServiceWorkerJob&, bool unregistrationResult) = 0;
     virtual void startScriptFetchForJob(ServiceWorkerJob&, FetchOptions::Cache) = 0;
     virtual void jobFinishedLoadingScript(ServiceWorkerJob&, const String& script, const ContentSecurityPolicyResponseHeaders&, const String& referrerPolicy) = 0;
-    virtual void jobFailedLoadingScript(ServiceWorkerJob&, const ResourceError&, Optional<Exception>&&) = 0;
+    virtual void jobFailedLoadingScript(ServiceWorkerJob&, const ResourceError&, Exception&&) = 0;
 
     virtual SWServerConnectionIdentifier connectionIdentifier() = 0;
-
-    virtual void ref() = 0;
-    virtual void deref() = 0;
 };
 
 } // namespace WebCore

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


--- trunk/Source/WebCore/workers/service/server/SWServerJobQueue.cpp	2019-01-30 20:27:45 UTC (rev 240726)
+++ trunk/Source/WebCore/workers/service/server/SWServerJobQueue.cpp	2019-01-30 21:00:30 UTC (rev 240727)
@@ -64,7 +64,8 @@
     auto& job = firstJob();
 
     auto* registration = m_server.getRegistration(m_registrationKey);
-    ASSERT(registration);
+    if (!registration)
+        return;
 
     auto* newestWorker = registration->getNewestWorker();
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to