90a19a582d40ecf9c2526305106591da407d719e
[WebKit-https.git] / Source / WebCore / workers / service / server / SWServerWorker.cpp
1 /*
2  * Copyright (C) 2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "SWServerWorker.h"
28
29 #if ENABLE(SERVICE_WORKER)
30
31 #include "SWServerToContextConnection.h"
32 #include <wtf/NeverDestroyed.h>
33
34 namespace WebCore {
35
36 HashMap<ServiceWorkerIdentifier, SWServerWorker*>& SWServerWorker::allWorkers()
37 {
38     static NeverDestroyed<HashMap<ServiceWorkerIdentifier, SWServerWorker*>> workers;
39     return workers;
40 }
41
42 SWServerWorker* SWServerWorker::existingWorkerForIdentifier(ServiceWorkerIdentifier identifier)
43 {
44     return allWorkers().get(identifier);
45 }
46
47 // FIXME: Use r-value references for script and contentSecurityPolicy
48 SWServerWorker::SWServerWorker(SWServer& server, SWServerRegistration& registration, const URL& scriptURL, const String& script, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicy, WorkerType type, ServiceWorkerIdentifier identifier)
49     : m_server(server)
50     , m_registrationKey(registration.key())
51     , m_data { identifier, scriptURL, ServiceWorkerState::Redundant, type, registration.identifier() }
52     , m_script(script)
53     , m_contentSecurityPolicy(contentSecurityPolicy)
54 {
55     m_data.scriptURL.removeFragmentIdentifier();
56
57     auto result = allWorkers().add(identifier, this);
58     ASSERT_UNUSED(result, result.isNewEntry);
59
60     ASSERT(m_server.getRegistration(m_registrationKey));
61 }
62
63 SWServerWorker::~SWServerWorker()
64 {
65     callWhenActivatedHandler(false);
66
67     auto taken = allWorkers().take(identifier());
68     ASSERT_UNUSED(taken, taken == this);
69 }
70
71 ServiceWorkerContextData SWServerWorker::contextData() const
72 {
73     auto* registration = m_server.getRegistration(m_registrationKey);
74     ASSERT(registration);
75
76     return { std::nullopt, registration->data(), m_data.identifier, m_script, m_contentSecurityPolicy, m_data.scriptURL, m_data.type, m_server.sessionID(), false };
77 }
78
79 void SWServerWorker::terminate()
80 {
81     if (isRunning())
82         m_server.terminateWorker(*this);
83 }
84
85 const ClientOrigin& SWServerWorker::origin() const
86 {
87     if (!m_origin)
88         m_origin = ClientOrigin { m_registrationKey.topOrigin(), SecurityOriginData::fromSecurityOrigin(SecurityOrigin::create(m_data.scriptURL)) };
89
90     return *m_origin;
91 }
92
93 Ref<SecurityOrigin> SWServerWorker::securityOrigin() const
94 {
95     return SecurityOrigin::create(m_data.scriptURL);
96 }
97
98 SWServerToContextConnection* SWServerWorker::contextConnection()
99 {
100     return SWServerToContextConnection::connectionForOrigin(securityOrigin());
101 }
102
103 void SWServerWorker::scriptContextFailedToStart(const std::optional<ServiceWorkerJobDataIdentifier>& jobDataIdentifier, const String& message)
104 {
105     m_server.scriptContextFailedToStart(jobDataIdentifier, *this, message);
106 }
107
108 void SWServerWorker::scriptContextStarted(const std::optional<ServiceWorkerJobDataIdentifier>& jobDataIdentifier)
109 {
110     m_server.scriptContextStarted(jobDataIdentifier, *this);
111 }
112
113 void SWServerWorker::didFinishInstall(const std::optional<ServiceWorkerJobDataIdentifier>& jobDataIdentifier, bool wasSuccessful)
114 {
115     m_server.didFinishInstall(jobDataIdentifier, *this, wasSuccessful);
116 }
117
118 void SWServerWorker::didFinishActivation()
119 {
120     m_server.didFinishActivation(*this);
121 }
122
123 void SWServerWorker::contextTerminated()
124 {
125     m_server.workerContextTerminated(*this);
126 }
127
128 std::optional<ServiceWorkerClientData> SWServerWorker::findClientByIdentifier(const ServiceWorkerClientIdentifier& clientId) const
129 {
130     return m_server.serviceWorkerClientWithOriginByID(origin(), clientId);
131 }
132
133 void SWServerWorker::matchAll(const ServiceWorkerClientQueryOptions& options, const ServiceWorkerClientsMatchAllCallback& callback)
134 {
135     return m_server.matchAll(*this, options, callback);
136 }
137
138 void SWServerWorker::claim()
139 {
140     return m_server.claim(*this);
141 }
142
143 void SWServerWorker::skipWaiting()
144 {
145     m_isSkipWaitingFlagSet = true;
146
147     auto* registration = m_server.getRegistration(m_registrationKey);
148     ASSERT(registration || isTerminating());
149     if (registration)
150         registration->tryActivate();
151 }
152
153 void SWServerWorker::setHasPendingEvents(bool hasPendingEvents)
154 {
155     if (m_hasPendingEvents == hasPendingEvents)
156         return;
157
158     m_hasPendingEvents = hasPendingEvents;
159     if (m_hasPendingEvents)
160         return;
161
162     // Do tryClear/tryActivate, as per https://w3c.github.io/ServiceWorker/#wait-until-method.
163     auto* registration = m_server.getRegistration(m_registrationKey);
164     if (!registration)
165         return;
166
167     if (registration->isUninstalling() && registration->tryClear())
168         return;
169     registration->tryActivate();
170 }
171
172 void SWServerWorker::whenActivated(WTF::Function<void(bool)>&& handler)
173 {
174     if (state() == ServiceWorkerState::Activated) {
175         handler(true);
176         return;
177     }
178     m_whenActivatedHandlers.append(WTFMove(handler));
179 }
180
181 void SWServerWorker::setState(ServiceWorkerState state)
182 {
183     if (state == ServiceWorkerState::Redundant)
184         terminate();
185
186     m_data.state = state;
187
188     auto* registration = m_server.getRegistration(m_registrationKey);
189     ASSERT(registration || state == ServiceWorkerState::Redundant);
190     if (registration) {
191         registration->forEachConnection([&](auto& connection) {
192             connection.updateWorkerStateInClient(this->identifier(), state);
193         });
194     }
195
196     if (state == ServiceWorkerState::Activated || state == ServiceWorkerState::Redundant)
197         callWhenActivatedHandler(state == ServiceWorkerState::Activated);
198 }
199
200 void SWServerWorker::callWhenActivatedHandler(bool success)
201 {
202     auto whenActivatedHandlers = WTFMove(m_whenActivatedHandlers);
203     for (auto& handler : whenActivatedHandlers)
204         handler(success);
205 }
206
207 void SWServerWorker::setState(State state)
208 {
209     ASSERT(state != State::Running || m_server.getRegistration(m_registrationKey));
210     m_state = state;
211 }
212
213 } // namespace WebCore
214
215 #endif // ENABLE(SERVICE_WORKER)