| Differences between
and this patch
- a/Source/WebCore/ChangeLog +52 lines
Lines 1-3 a/Source/WebCore/ChangeLog_sec1
1
2018-01-16  Chris Dumez  <cdumez@apple.com>
2
3
        'fetch' event may be sent to a service worker before its state is set to 'activated'
4
        https://bugs.webkit.org/show_bug.cgi?id=181698
5
        <rdar://problem/36554856>
6
7
        Reviewed by NOBODY (OOPS!).
8
9
        'fetch' event may be sent to a service worker before its state is set to 'activated'.
10
        When the registration's active worker needs to intercept a load, and its state is 'activating',
11
        we queue the request to send the fetch event in SWServerWorker::m_whenActivatedHandlers.
12
        Once the SWServerWorker::setState() is called with 'activated' state, we then call the
13
        handlers in m_whenActivatedHandlers to make send the fetch event now that the worker is
14
        activated. The issue is that even though the worker is activated and its state was set to
15
        'activated' on Storage process side, we had not yet notified the ServiceWorker process
16
        of the service worker's new state yet.
17
18
        To address the issue, we now make sure that SWServerWorker::m_whenActivatedHandlers are
19
        called *after* we've sent the IPC to the ServiceWorker process to update the worker's
20
        state to 'activated'. Also, we now call ServiceWorkerFetch::dispatchFetchEvent()
21
        asynchronously in a postTask() as the service worker's state is also updated asynchronously
22
        in a postTask. This is as per specification [1], which says to "queue a task" to fire
23
        the fetch event.
24
25
        [1] https://w3c.github.io/ServiceWorker/#on-fetch-request-algorithm (step 18)
26
27
        No new tests, covered by imported/w3c/web-platform-tests/service-workers/service-worker/fetch-waits-for-activate.https.html
28
        which hits the new assertion without the fix.
29
30
        * workers/service/context/ServiceWorkerFetch.cpp:
31
        (WebCore::ServiceWorkerFetch::dispatchFetchEvent):
32
        Add assertions to make sure that the we dispatch the fetch event on a the right worker and
33
        that the worker is in 'activated' state.
34
35
        * workers/service/context/ServiceWorkerThread.cpp:
36
        (WebCore::ServiceWorkerThread::postFetchTask):
37
        Queue a task to fire the fetch event as per:
38
        - https://w3c.github.io/ServiceWorker/#on-fetch-request-algorithm (step 18)
39
        We need to match the specification exactly here or things will happen in the wrong
40
        order.
41
42
        * workers/service/server/SWServerRegistration.cpp:
43
        (WebCore::SWServerRegistration::updateWorkerState):
44
        * workers/service/server/SWServerRegistration.h:
45
        * workers/service/server/SWServerWorker.cpp:
46
        (WebCore::SWServerWorker::setState):
47
        Move code to send the IPC to the Service Worker process whenever the service worker's state
48
        needs to be updated from SWServerRegistration::updateWorkerState() to SWServerWorker::setState().
49
        This way, we can make sure the IPC is sent *before* we call the m_whenActivatedHandlers handlers,
50
        as they may also send IPC to the Service Worker process, and we need to make sure this IPC happens
51
        after so that the service worker is in the right state.
52
1
2018-01-16  Chris Dumez  <cdumez@apple.com>
53
2018-01-16  Chris Dumez  <cdumez@apple.com>
2
54
3
        SWServerWorker::m_contextConnectionIdentifier may get out of date
55
        SWServerWorker::m_contextConnectionIdentifier may get out of date
- a/Source/WebCore/workers/service/context/ServiceWorkerFetch.cpp +5 lines
Lines 34-39 a/Source/WebCore/workers/service/context/ServiceWorkerFetch.cpp_sec1
34
#include "FetchRequest.h"
34
#include "FetchRequest.h"
35
#include "FetchResponse.h"
35
#include "FetchResponse.h"
36
#include "ResourceRequest.h"
36
#include "ResourceRequest.h"
37
#include "ServiceWorker.h"
37
#include "ServiceWorkerClientIdentifier.h"
38
#include "ServiceWorkerClientIdentifier.h"
38
#include "WorkerGlobalScope.h"
39
#include "WorkerGlobalScope.h"
39
40
Lines 98-103 void dispatchFetchEvent(Ref<Client>&& client, ServiceWorkerGlobalScope& globalSc a/Source/WebCore/workers/service/context/ServiceWorkerFetch.cpp_sec2
98
    bool isNavigation = options.mode == FetchOptions::Mode::Navigate;
99
    bool isNavigation = options.mode == FetchOptions::Mode::Navigate;
99
    bool isNonSubresourceRequest = WebCore::isNonSubresourceRequest(options.destination);
100
    bool isNonSubresourceRequest = WebCore::isNonSubresourceRequest(options.destination);
100
101
102
    ASSERT(globalScope.registration().active());
103
    ASSERT(globalScope.registration().active()->identifier() == globalScope.thread().identifier());
104
    ASSERT(globalScope.registration().active()->state() == ServiceWorkerState::Activated);
105
101
    auto* formData = request.httpBody();
106
    auto* formData = request.httpBody();
102
    std::optional<FetchBody> body;
107
    std::optional<FetchBody> body;
103
    if (formData && !formData->isEmpty()) {
108
    if (formData && !formData->isEmpty()) {
- a/Source/WebCore/workers/service/context/ServiceWorkerThread.cpp -1 / +3 lines
Lines 96-102 void ServiceWorkerThread::postFetchTask(Ref<ServiceWorkerFetch::Client>&& client a/Source/WebCore/workers/service/context/ServiceWorkerThread.cpp_sec1
96
    // FIXME: instead of directly using runLoop(), we should be using something like WorkerGlobalScopeProxy.
96
    // FIXME: instead of directly using runLoop(), we should be using something like WorkerGlobalScopeProxy.
97
    // FIXME: request and options come straigth from IPC so are already isolated. We should be able to take benefit of that.
97
    // FIXME: request and options come straigth from IPC so are already isolated. We should be able to take benefit of that.
98
    runLoop().postTaskForMode([client = WTFMove(client), clientId, request = request.isolatedCopy(), referrer = referrer.isolatedCopy(), options = options.isolatedCopy()] (ScriptExecutionContext& context) mutable {
98
    runLoop().postTaskForMode([client = WTFMove(client), clientId, request = request.isolatedCopy(), referrer = referrer.isolatedCopy(), options = options.isolatedCopy()] (ScriptExecutionContext& context) mutable {
99
        ServiceWorkerFetch::dispatchFetchEvent(WTFMove(client), downcast<ServiceWorkerGlobalScope>(context), clientId, WTFMove(request), WTFMove(referrer), WTFMove(options));
99
        context.postTask([client = WTFMove(client), clientId, request = WTFMove(request), referrer = WTFMove(referrer), options = WTFMove(options)] (ScriptExecutionContext& context) mutable {
100
            ServiceWorkerFetch::dispatchFetchEvent(WTFMove(client), downcast<ServiceWorkerGlobalScope>(context), clientId, WTFMove(request), WTFMove(referrer), WTFMove(options));
101
        });
100
    }, WorkerRunLoop::defaultMode());
102
    }, WorkerRunLoop::defaultMode());
101
}
103
}
102
104
- a/Source/WebCore/workers/service/server/SWServerRegistration.cpp -4 lines
Lines 102-111 void SWServerRegistration::updateWorkerState(SWServerWorker& worker, ServiceWork a/Source/WebCore/workers/service/server/SWServerRegistration.cpp_sec1
102
    LOG(ServiceWorker, "Updating worker %p state to %i (%p)", &worker, (int)state, this);
102
    LOG(ServiceWorker, "Updating worker %p state to %i (%p)", &worker, (int)state, this);
103
103
104
    worker.setState(state);
104
    worker.setState(state);
105
106
    forEachConnection([&](auto& connection) {
107
        connection.updateWorkerStateInClient(worker.identifier(), state);
108
    });
109
}
105
}
110
106
111
void SWServerRegistration::setUpdateViaCache(ServiceWorkerUpdateViaCache updateViaCache)
107
void SWServerRegistration::setUpdateViaCache(ServiceWorkerUpdateViaCache updateViaCache)
- a/Source/WebCore/workers/service/server/SWServerRegistration.h -1 / +1 lines
Lines 92-100 public: a/Source/WebCore/workers/service/server/SWServerRegistration.h_sec1
92
    void tryActivate();
92
    void tryActivate();
93
    void didFinishActivation(ServiceWorkerIdentifier);
93
    void didFinishActivation(ServiceWorkerIdentifier);
94
94
95
private:
96
    void forEachConnection(const WTF::Function<void(SWServer::Connection&)>&);
95
    void forEachConnection(const WTF::Function<void(SWServer::Connection&)>&);
97
96
97
private:
98
    void activate();
98
    void activate();
99
    void handleClientUnload();
99
    void handleClientUnload();
100
100
- a/Source/WebCore/workers/service/server/SWServerWorker.cpp +6 lines
Lines 175-180 void SWServerWorker::setState(ServiceWorkerState state) a/Source/WebCore/workers/service/server/SWServerWorker.cpp_sec1
175
175
176
    m_data.state = state;
176
    m_data.state = state;
177
177
178
    if (auto* registration = m_server.getRegistration(m_registrationKey)) {
179
        registration->forEachConnection([&](auto& connection) {
180
            connection.updateWorkerStateInClient(identifier(), state);
181
        });
182
    }
183
178
    if (state == ServiceWorkerState::Activated || state == ServiceWorkerState::Redundant)
184
    if (state == ServiceWorkerState::Activated || state == ServiceWorkerState::Redundant)
179
        callWhenActivatedHandler(state == ServiceWorkerState::Activated);
185
        callWhenActivatedHandler(state == ServiceWorkerState::Activated);
180
}
186
}

Return to Bug 181698