Changeset 240727 in webkit


Ignore:
Timestamp:
Jan 30, 2019 1:00:30 PM (5 years ago)
Author:
youenn@apple.com
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):

Location:
trunk
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r240706 r240727  
     12019-01-30  Youenn Fablet  <youenn@apple.com>
     2
     3        ServiceWorkerJob should notify its client in case its job is cancelled
     4        https://bugs.webkit.org/show_bug.cgi?id=193747
     5        <rdar://problem/47498196>
     6
     7        Reviewed by Chris Dumez.
     8
     9        * web-platform-tests/service-workers/service-worker/registration-security-error.https-expected.txt:
     10
    1112019-01-29  Rob Buis  <rbuis@igalia.com>
    212
  • trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/registration-security-error.https-expected.txt

    r238592 r240727  
    44PASS Registering scope outside domain
    55PASS Registering script outside domain
    6 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
     6PASS Registering redirected script
    77PASS Scope including parent-reference and not under the script directory
    88PASS Script URL including consecutive slashes
  • trunk/Source/WebCore/ChangeLog

    r240721 r240727  
     12019-01-30  Youenn Fablet  <youenn@apple.com>
     2
     3        Refactor ServiceWorkerJob management by ServiceWorkerContainer to make it more memory safe
     4        https://bugs.webkit.org/show_bug.cgi?id=193747
     5        <rdar://problem/47498196>
     6
     7        Reviewed by Chris Dumez.
     8
     9        Make ServiceWorkerJob be no longer ref counted.
     10        Instead its lifetime is fully controlled by ServiceWorkerContainer.
     11
     12        Make sure that a failing load will remove the job from ServiceWorkerContainer job map.
     13        This allows to ensure that these jobs do not stay forever.
     14        Before the patch, the jobs map was never cleared, which is creating a ref cycle whenever a job is not succesful.
     15
     16        Before the patch, unsetPendingActivity was only called for successful jobs finishing.
     17        In case of failing loads, ServiceWorkerContainer would leak.
     18        Make sure that setPendingActivity/unsetPendingActivity is balanced by storing
     19        a pending activity in the job map next to the job.
     20
     21        When ServiceWorkerContainer is stopped, notify that all jobs are cancelled to NetworkProcess.
     22        This makes these jobs in NetworkProcess-side to not stay until the corresponding WebProcess is gone.
     23
     24        Simplify ServiceWorkerJob promise rejection handling so that it is clear when promise is rejected and when it is not.
     25        Update type of exception to be SecurityError when load fails due to AccessControl.
     26
     27        Covered by existing tests.
     28
     29        * workers/service/ServiceWorkerContainer.cpp:
     30        (WebCore::ServiceWorkerContainer::addRegistration):
     31        (WebCore::ServiceWorkerContainer::removeRegistration):
     32        (WebCore::ServiceWorkerContainer::updateRegistration):
     33        (WebCore::ServiceWorkerContainer::scheduleJob):
     34        (WebCore::ServiceWorkerContainer::jobFailedWithException):
     35        (WebCore::ServiceWorkerContainer::jobResolvedWithRegistration):
     36        (WebCore::ServiceWorkerContainer::jobResolvedWithUnregistrationResult):
     37        (WebCore::ServiceWorkerContainer::jobFailedLoadingScript):
     38        (WebCore::ServiceWorkerContainer::jobDidFinish):
     39        (WebCore::ServiceWorkerContainer::stop):
     40        (WebCore::ServiceWorkerContainer::job):
     41        * workers/service/ServiceWorkerContainer.h:
     42        * workers/service/ServiceWorkerJob.cpp:
     43        (WebCore::ServiceWorkerJob::failedWithException):
     44        (WebCore::ServiceWorkerJob::resolvedWithRegistration):
     45        (WebCore::ServiceWorkerJob::resolvedWithUnregistrationResult):
     46        (WebCore::ServiceWorkerJob::startScriptFetch):
     47        (WebCore::ServiceWorkerJob::didReceiveResponse):
     48        (WebCore::ServiceWorkerJob::notifyFinished):
     49        (WebCore::ServiceWorkerJob::cancelPendingLoad):
     50        * workers/service/ServiceWorkerJob.h:
     51        (WebCore::ServiceWorkerJob::hasPromise const):
     52        (WebCore::ServiceWorkerJob::takePromise):
     53        * workers/service/ServiceWorkerJobClient.h:
     54        * workers/service/server/SWServerJobQueue.cpp:
     55        (WebCore::SWServerJobQueue::scriptFetchFinished):
     56
    1572019-01-30  Dean Jackson  <dino@apple.com>
    258
  • trunk/Source/WebCore/workers/service/ServiceWorkerContainer.cpp

    r240237 r240727  
    177177    jobData.registrationOptions = options;
    178178
    179     scheduleJob(ServiceWorkerJob::create(*this, WTFMove(promise), WTFMove(jobData)));
     179    scheduleJob(std::make_unique<ServiceWorkerJob>(*this, WTFMove(promise), WTFMove(jobData)));
    180180}
    181181
     
    203203    CONTAINER_RELEASE_LOG_IF_ALLOWED("removeRegistration: Unregistering service worker. Job ID: %" PRIu64, jobData.identifier().jobIdentifier.toUInt64());
    204204
    205     scheduleJob(ServiceWorkerJob::create(*this, WTFMove(promise), WTFMove(jobData)));
     205    scheduleJob(std::make_unique<ServiceWorkerJob>(*this, WTFMove(promise), WTFMove(jobData)));
    206206}
    207207
     
    229229    CONTAINER_RELEASE_LOG_IF_ALLOWED("removeRegistration: Updating service worker. Job ID: %" PRIu64, jobData.identifier().jobIdentifier.toUInt64());
    230230
    231     scheduleJob(ServiceWorkerJob::create(*this, WTFMove(promise), WTFMove(jobData)));
    232 }
    233 
    234 void ServiceWorkerContainer::scheduleJob(Ref<ServiceWorkerJob>&& job)
     231    scheduleJob(std::make_unique<ServiceWorkerJob>(*this, WTFMove(promise), WTFMove(jobData)));
     232}
     233
     234void ServiceWorkerContainer::scheduleJob(std::unique_ptr<ServiceWorkerJob>&& job)
    235235{
    236236#ifndef NDEBUG
     
    239239
    240240    ASSERT(m_swConnection);
    241 
    242     setPendingActivity(*this);
     241    ASSERT(!isStopped());
    243242
    244243    auto& jobData = job->data();
    245     auto result = m_jobMap.add(job->identifier(), WTFMove(job));
    246     ASSERT_UNUSED(result, result.isNewEntry);
     244    auto jobIdentifier = job->identifier();
     245    ASSERT(!m_jobMap.contains(jobIdentifier));
     246    m_jobMap.add(jobIdentifier, OngoingJob { WTFMove(job), makePendingActivity(*this) });
    247247
    248248    callOnMainThread([connection = m_swConnection, contextIdentifier = this->contextIdentifier(), jobData = jobData.isolatedCopy()] {
     
    386386#endif
    387387
    388     ASSERT_WITH_MESSAGE(job.promise() || job.data().type == ServiceWorkerJobType::Update, "Only soft updates have no promise");
     388    ASSERT_WITH_MESSAGE(job.hasPromise() || job.data().type == ServiceWorkerJobType::Update, "Only soft updates have no promise");
    389389
    390390    auto guard = WTF::makeScopeExit([this, &job] {
    391         jobDidFinish(job);
     391        destroyJob(job);
    392392    });
    393393
    394394    CONTAINER_RELEASE_LOG_ERROR_IF_ALLOWED("jobFailedWithException: Job %" PRIu64 " failed with error %s", job.identifier().toUInt64(), exception.message().utf8().data());
    395395
    396     if (!job.promise())
     396    auto promise = job.takePromise();
     397    if (!promise)
    397398        return;
    398399
    399400    if (auto* context = scriptExecutionContext()) {
    400         context->postTask([job = makeRef(job), exception](ScriptExecutionContext&) {
    401             job->promise()->reject(exception);
     401        context->postTask([promise = WTFMove(promise), exception](auto&) mutable {
     402            promise->reject(exception);
    402403        });
    403404    }
     
    419420    ASSERT(m_creationThread.ptr() == &Thread::current());
    420421#endif
    421     ASSERT_WITH_MESSAGE(job.promise() || job.data().type == ServiceWorkerJobType::Update, "Only soft updates have no promise");
     422    ASSERT_WITH_MESSAGE(job.hasPromise() || job.data().type == ServiceWorkerJobType::Update, "Only soft updates have no promise");
    422423
    423424    auto guard = WTF::makeScopeExit([this, &job] {
    424         jobDidFinish(job);
     425        destroyJob(job);
    425426    });
    426427
     
    447448    }
    448449
    449     if (!job.promise()) {
     450    auto promise = job.takePromise();
     451    if (!promise) {
    450452        if (notifyWhenResolvedIfNeeded)
    451453            notifyWhenResolvedIfNeeded();
     
    453455    }
    454456
    455     scriptExecutionContext()->postTask([this, protectedThis = makeRef(*this), job = makeRef(job), data = WTFMove(data), notifyWhenResolvedIfNeeded = WTFMove(notifyWhenResolvedIfNeeded)](ScriptExecutionContext& context) mutable {
     457    scriptExecutionContext()->postTask([this, protectedThis = makeRef(*this), promise = WTFMove(promise), jobIdentifier = job.identifier(), data = WTFMove(data), notifyWhenResolvedIfNeeded = WTFMove(notifyWhenResolvedIfNeeded)](ScriptExecutionContext& context) mutable {
    456458        if (isStopped() || !context.sessionID().isValid()) {
    457459            if (notifyWhenResolvedIfNeeded)
     
    462464        auto registration = ServiceWorkerRegistration::getOrCreate(context, *this, WTFMove(data));
    463465
    464         CONTAINER_RELEASE_LOG_IF_ALLOWED("jobResolvedWithRegistration: Resolving promise for job %" PRIu64 ". Registration ID: %" PRIu64, job->identifier().toUInt64(), registration->identifier().toUInt64());
     466        CONTAINER_RELEASE_LOG_IF_ALLOWED("jobResolvedWithRegistration: Resolving promise for job %" PRIu64 ". Registration ID: %" PRIu64, jobIdentifier.toUInt64(), registration->identifier().toUInt64());
    465467
    466468        if (notifyWhenResolvedIfNeeded) {
    467             job->promise()->whenSettled([notifyWhenResolvedIfNeeded = WTFMove(notifyWhenResolvedIfNeeded)] {
     469            promise->whenSettled([notifyWhenResolvedIfNeeded = WTFMove(notifyWhenResolvedIfNeeded)] {
    468470                notifyWhenResolvedIfNeeded();
    469471            });
    470472        }
    471473
    472         job->promise()->resolve<IDLInterface<ServiceWorkerRegistration>>(WTFMove(registration));
     474        promise->resolve<IDLInterface<ServiceWorkerRegistration>>(WTFMove(registration));
    473475    });
    474476}
     
    480482#endif
    481483
    482     ASSERT(job.promise());
     484    ASSERT(job.hasPromise());
    483485
    484486    auto guard = WTF::makeScopeExit([this, &job] {
    485         jobDidFinish(job);
     487        destroyJob(job);
    486488    });
    487489
     
    494496    }
    495497
    496     context->postTask([job = makeRef(job), unregistrationResult](ScriptExecutionContext&) mutable {
    497         job->promise()->resolve<IDLBoolean>(unregistrationResult);
     498    context->postTask([promise = job.takePromise(), unregistrationResult](auto&) mutable {
     499        promise->resolve<IDLBoolean>(unregistrationResult);
    498500    });
    499501}
     
    510512    if (!context) {
    511513        LOG_ERROR("ServiceWorkerContainer::jobResolvedWithRegistration called but the container's ScriptExecutionContext is gone");
    512         callOnMainThread([connection = m_swConnection, jobIdentifier = job.identifier(), registrationKey = job.data().registrationKey().isolatedCopy(), scriptURL = job.data().scriptURL.isolatedCopy()] {
    513             connection->failedFetchingScript(jobIdentifier, registrationKey, { errorDomainWebKitInternal, 0, scriptURL, "Attempt to fetch service worker script with no ScriptExecutionContext"_s });
    514         });
    515         jobDidFinish(job);
     514        notifyFailedFetchingScript(job, { errorDomainWebKitInternal, 0, job.data().scriptURL, "Attempt to fetch service worker script with no ScriptExecutionContext"_s });
     515        destroyJob(job);
    516516        return;
    517517    }
     
    533533}
    534534
    535 void ServiceWorkerContainer::jobFailedLoadingScript(ServiceWorkerJob& job, const ResourceError& error, Optional<Exception>&& exception)
    536 {
    537 #ifndef NDEBUG
    538     ASSERT(m_creationThread.ptr() == &Thread::current());
    539 #endif
    540     ASSERT_WITH_MESSAGE(job.promise() || job.data().type == ServiceWorkerJobType::Update, "Only soft updates have no promise");
     535void ServiceWorkerContainer::jobFailedLoadingScript(ServiceWorkerJob& job, const ResourceError& error, Exception&& exception)
     536{
     537#ifndef NDEBUG
     538    ASSERT(m_creationThread.ptr() == &Thread::current());
     539#endif
     540    ASSERT_WITH_MESSAGE(job.hasPromise() || job.data().type == ServiceWorkerJobType::Update, "Only soft updates have no promise");
    541541
    542542    CONTAINER_RELEASE_LOG_ERROR_IF_ALLOWED("jobFinishedLoadingScript: Failed to fetch script for job %" PRIu64 ", error: %s", job.identifier().toUInt64(), error.localizedDescription().utf8().data());
    543543
    544     if (exception && job.promise())
    545         job.promise()->reject(*exception);
    546 
     544    if (auto promise = job.takePromise())
     545        promise->reject(WTFMove(exception));
     546
     547    notifyFailedFetchingScript(job, error);
     548    destroyJob(job);
     549}
     550
     551void ServiceWorkerContainer::notifyFailedFetchingScript(ServiceWorkerJob& job, const ResourceError& error)
     552{
    547553    callOnMainThread([connection = m_swConnection, jobIdentifier = job.identifier(), registrationKey = job.data().registrationKey().isolatedCopy(), error = error.isolatedCopy()] {
    548554        connection->failedFetchingScript(jobIdentifier, registrationKey, error);
     
    550556}
    551557
    552 void ServiceWorkerContainer::jobDidFinish(ServiceWorkerJob& job)
    553 {
    554 #ifndef NDEBUG
    555     ASSERT(m_creationThread.ptr() == &Thread::current());
    556 #endif
    557 
    558     auto taken = m_jobMap.take(job.identifier());
    559     ASSERT_UNUSED(taken, !taken || taken->ptr() == &job);
    560 
    561     unsetPendingActivity(*this);
     558void ServiceWorkerContainer::destroyJob(ServiceWorkerJob& job)
     559{
     560#ifndef NDEBUG
     561    ASSERT(m_creationThread.ptr() == &Thread::current());
     562#endif
     563
     564    ASSERT(m_jobMap.contains(job.identifier()));
     565    m_jobMap.remove(job.identifier());
    562566}
    563567
     
    634638    m_pendingPromises.clear();
    635639    m_readyPromise = nullptr;
    636     for (auto& job : m_jobMap.values())
    637         job->cancelPendingLoad();
     640    auto jobMap = WTFMove(m_jobMap);
     641    for (auto& ongoingJob : jobMap.values()) {
     642        notifyFailedFetchingScript(*ongoingJob.job.get(), ResourceError { errorDomainWebKitInternal, 0, ongoingJob.job->data().scriptURL, "Job cancelled"_s, ResourceError::Type::Cancellation });
     643        ongoingJob.job->cancelPendingLoad();
     644    }
    638645}
    639646
     
    650657}
    651658
     659ServiceWorkerJob* ServiceWorkerContainer::job(ServiceWorkerJobIdentifier identifier)
     660{
     661    auto iterator = m_jobMap.find(identifier);
     662    if (iterator == m_jobMap.end())
     663        return nullptr;
     664    return iterator->value.job.get();
     665}
     666
    652667bool ServiceWorkerContainer::isAlwaysOnLoggingAllowed() const
    653668{
  • trunk/Source/WebCore/workers/service/ServiceWorkerContainer.h

    r239659 r240727  
    7878    void removeRegistration(ServiceWorkerRegistration&);
    7979
    80     ServiceWorkerJob* job(ServiceWorkerJobIdentifier identifier) { return m_jobMap.get(identifier); }
     80    ServiceWorkerJob* job(ServiceWorkerJobIdentifier);
    8181
    8282    void startMessages();
    83 
    84     void ref() final { refEventTarget(); }
    85     void deref() final { derefEventTarget(); }
    8683
    8784    bool isStopped() const { return m_isStopped; };
     
    9087
    9188private:
    92     void scheduleJob(Ref<ServiceWorkerJob>&&);
     89    void scheduleJob(std::unique_ptr<ServiceWorkerJob>&&);
    9390
    9491    void jobFailedWithException(ServiceWorkerJob&, const Exception&) final;
     
    9794    void startScriptFetchForJob(ServiceWorkerJob&, FetchOptions::Cache) final;
    9895    void jobFinishedLoadingScript(ServiceWorkerJob&, const String& script, const ContentSecurityPolicyResponseHeaders&, const String& referrerPolicy) final;
    99     void jobFailedLoadingScript(ServiceWorkerJob&, const ResourceError&, Optional<Exception>&&) final;
     96    void jobFailedLoadingScript(ServiceWorkerJob&, const ResourceError&, Exception&&) final;
    10097
    101     void jobDidFinish(ServiceWorkerJob&);
     98    void notifyFailedFetchingScript(ServiceWorkerJob&, const ResourceError&);
     99    void destroyJob(ServiceWorkerJob&);
    102100
    103101    void didFinishGetRegistrationRequest(uint64_t requestIdentifier, Optional<ServiceWorkerRegistrationData>&&);
     
    122120
    123121    RefPtr<SWClientConnection> m_swConnection;
    124     HashMap<ServiceWorkerJobIdentifier, Ref<ServiceWorkerJob>> m_jobMap;
     122
     123    struct OngoingJob {
     124        std::unique_ptr<ServiceWorkerJob> job;
     125        RefPtr<PendingActivity<ServiceWorkerContainer>> pendingActivity;
     126    };
     127    HashMap<ServiceWorkerJobIdentifier, OngoingJob> m_jobMap;
    125128
    126129    bool m_isStopped { false };
  • trunk/Source/WebCore/workers/service/ServiceWorkerJob.cpp

    r239659 r240727  
    5858
    5959    m_completed = true;
    60     m_client->jobFailedWithException(*this, exception);
     60    m_client.jobFailedWithException(*this, exception);
    6161}
    6262
     
    6767
    6868    m_completed = true;
    69     m_client->jobResolvedWithRegistration(*this, WTFMove(data), shouldNotifyWhenResolved);
     69    m_client.jobResolvedWithRegistration(*this, WTFMove(data), shouldNotifyWhenResolved);
    7070}
    7171
     
    7676
    7777    m_completed = true;
    78     m_client->jobResolvedWithUnregistrationResult(*this, unregistrationResult);
     78    m_client.jobResolvedWithUnregistrationResult(*this, unregistrationResult);
    7979}
    8080
     
    8484    ASSERT(!m_completed);
    8585
    86     m_client->startScriptFetchForJob(*this, cachePolicy);
     86    m_client.startScriptFetchForJob(*this, cachePolicy);
    8787}
    8888
     
    115115    // Extract a MIME type from the response's header list. If this MIME type (ignoring parameters) is not a JavaScript MIME type, then:
    116116    if (!MIMETypeRegistry::isSupportedJavaScriptMIMEType(response.mimeType())) {
     117        m_scriptLoader->cancel();
     118        m_scriptLoader = nullptr;
     119
    117120        // Invoke Reject Job Promise with job and "SecurityError" DOMException.
    118121        Exception exception { SecurityError, "MIME Type is not a JavaScript MIME type"_s };
    119122        // Asynchronously complete these steps with a network error.
    120123        ResourceError error { errorDomainWebKitInternal, 0, response.url(), "Unexpected MIME type"_s };
    121         m_client->jobFailedLoadingScript(*this, WTFMove(error), WTFMove(exception));
    122         m_scriptLoader = nullptr;
     124        m_client.jobFailedLoadingScript(*this, WTFMove(error), WTFMove(exception));
     125        return;
    123126    }
     127
    124128    String serviceWorkerAllowed = response.httpHeaderField(HTTPHeaderName::ServiceWorkerAllowed);
    125129    String maxScopeString;
     
    132136        maxScopeString = maxScope.path();
    133137    }
     138
    134139    String scopeString = m_jobData.scopeURL.path();
    135     if (!scopeString.startsWith(maxScopeString)) {
    136         Exception exception { SecurityError, "Scope URL should start with the given script URL"_s };
    137         ResourceError error { errorDomainWebKitInternal, 0, response.url(), "Scope URL should start with the given script URL"_s };
    138         m_client->jobFailedLoadingScript(*this, WTFMove(error), WTFMove(exception));
    139         m_scriptLoader = nullptr;
    140     }
     140    if (scopeString.startsWith(maxScopeString))
     141        return;
     142
     143    m_scriptLoader->cancel();
     144    m_scriptLoader = nullptr;
     145
     146    Exception exception { SecurityError, "Scope URL should start with the given script URL"_s };
     147    ResourceError error { errorDomainWebKitInternal, 0, response.url(), "Scope URL should start with the given script URL"_s };
     148    m_client.jobFailedLoadingScript(*this, WTFMove(error), WTFMove(exception));
    141149}
    142150
     
    146154    ASSERT(m_scriptLoader);
    147155   
    148     if (!m_scriptLoader->failed())
    149         m_client->jobFinishedLoadingScript(*this, m_scriptLoader->script(), m_scriptLoader->contentSecurityPolicy(), m_scriptLoader->referrerPolicy());
    150     else {
    151         auto& error =  m_scriptLoader->error();
    152         ASSERT(!error.isNull());
    153         m_client->jobFailedLoadingScript(*this, error, WTF::nullopt);
     156    auto scriptLoader = WTFMove(m_scriptLoader);
     157
     158    if (!scriptLoader->failed()) {
     159        m_client.jobFinishedLoadingScript(*this, scriptLoader->script(), scriptLoader->contentSecurityPolicy(), scriptLoader->referrerPolicy());
     160        return;
    154161    }
    155162
    156     m_scriptLoader = nullptr;
     163    auto& error = scriptLoader->error();
     164    ASSERT(!error.isNull());
     165
     166    m_client.jobFailedLoadingScript(*this, error, Exception { error.isAccessControl() ? SecurityError : TypeError, "Script load failed"_s });
    157167}
    158168
  • trunk/Source/WebCore/workers/service/ServiceWorkerJob.h

    r230374 r240727  
    2828#if ENABLE(SERVICE_WORKER)
    2929
     30#include "JSDOMPromiseDeferred.h"
    3031#include "ResourceResponse.h"
    3132#include "ServiceWorkerJobClient.h"
     
    4748struct ServiceWorkerRegistrationData;
    4849
    49 class ServiceWorkerJob : public ThreadSafeRefCounted<ServiceWorkerJob>, public WorkerScriptLoaderClient {
     50class ServiceWorkerJob : public WorkerScriptLoaderClient {
     51    WTF_MAKE_FAST_ALLOCATED;
    5052public:
    51     static Ref<ServiceWorkerJob> create(ServiceWorkerJobClient& client, RefPtr<DeferredPromise>&& promise, ServiceWorkerJobData&& jobData)
    52     {
    53         return adoptRef(*new ServiceWorkerJob(client, WTFMove(promise), WTFMove(jobData)));
    54     }
    55 
     53    ServiceWorkerJob(ServiceWorkerJobClient&, RefPtr<DeferredPromise>&&, ServiceWorkerJobData&&);
    5654    WEBCORE_EXPORT ~ServiceWorkerJob();
    5755
     
    6563
    6664    const ServiceWorkerJobData& data() const { return m_jobData; }
    67     DeferredPromise* promise() { return m_promise.get(); }
     65    bool hasPromise() const { return !!m_promise; }
     66    RefPtr<DeferredPromise> takePromise() { return WTFMove(m_promise); }
    6867
    6968    void fetchScriptWithContext(ScriptExecutionContext&, FetchOptions::Cache);
     
    7473
    7574private:
    76     ServiceWorkerJob(ServiceWorkerJobClient&, RefPtr<DeferredPromise>&&, ServiceWorkerJobData&&);
    77 
    7875    // WorkerScriptLoaderClient
    7976    void didReceiveResponse(unsigned long identifier, const ResourceResponse&) final;
    8077    void notifyFinished() final;
    8178
    82     Ref<ServiceWorkerJobClient> m_client;
     79    ServiceWorkerJobClient& m_client;
    8380    ServiceWorkerJobData m_jobData;
    8481    RefPtr<DeferredPromise> m_promise;
  • trunk/Source/WebCore/workers/service/ServiceWorkerJobClient.h

    r239659 r240727  
    5151    virtual void startScriptFetchForJob(ServiceWorkerJob&, FetchOptions::Cache) = 0;
    5252    virtual void jobFinishedLoadingScript(ServiceWorkerJob&, const String& script, const ContentSecurityPolicyResponseHeaders&, const String& referrerPolicy) = 0;
    53     virtual void jobFailedLoadingScript(ServiceWorkerJob&, const ResourceError&, Optional<Exception>&&) = 0;
     53    virtual void jobFailedLoadingScript(ServiceWorkerJob&, const ResourceError&, Exception&&) = 0;
    5454
    5555    virtual SWServerConnectionIdentifier connectionIdentifier() = 0;
    56 
    57     virtual void ref() = 0;
    58     virtual void deref() = 0;
    5956};
    6057
  • trunk/Source/WebCore/workers/service/server/SWServerJobQueue.cpp

    r239659 r240727  
    6565
    6666    auto* registration = m_server.getRegistration(m_registrationKey);
    67     ASSERT(registration);
     67    if (!registration)
     68        return;
    6869
    6970    auto* newestWorker = registration->getNewestWorker();
Note: See TracChangeset for help on using the changeset viewer.