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 "SWServer.h" |
32 | #include "SWServerRegistration.h" |
33 | #include "SWServerToContextConnection.h" |
34 | #include <wtf/NeverDestroyed.h> |
35 | |
36 | namespace WebCore { |
37 | |
38 | HashMap<ServiceWorkerIdentifier, SWServerWorker*>& SWServerWorker::allWorkers() |
39 | { |
40 | static NeverDestroyed<HashMap<ServiceWorkerIdentifier, SWServerWorker*>> workers; |
41 | return workers; |
42 | } |
43 | |
44 | SWServerWorker* SWServerWorker::existingWorkerForIdentifier(ServiceWorkerIdentifier identifier) |
45 | { |
46 | return allWorkers().get(identifier); |
47 | } |
48 | |
49 | // FIXME: Use r-value references for script and contentSecurityPolicy |
50 | SWServerWorker::(SWServer& server, SWServerRegistration& registration, const URL& scriptURL, const String& script, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicy, String&& referrerPolicy, WorkerType type, ServiceWorkerIdentifier identifier, HashMap<URL, ServiceWorkerContextData::ImportedScript>&& scriptResourceMap) |
51 | : m_server(server) |
52 | , m_registrationKey(registration.key()) |
53 | , m_data { identifier, scriptURL, ServiceWorkerState::Redundant, type, registration.identifier() } |
54 | , m_script(script) |
55 | , m_contentSecurityPolicy(contentSecurityPolicy) |
56 | , m_referrerPolicy(WTFMove(referrerPolicy)) |
57 | , m_registrableDomain(m_data.scriptURL) |
58 | , m_scriptResourceMap(WTFMove(scriptResourceMap)) |
59 | { |
60 | m_data.scriptURL.removeFragmentIdentifier(); |
61 | |
62 | auto result = allWorkers().add(identifier, this); |
63 | ASSERT_UNUSED(result, result.isNewEntry); |
64 | |
65 | ASSERT(m_server.getRegistration(m_registrationKey)); |
66 | } |
67 | |
68 | SWServerWorker::~SWServerWorker() |
69 | { |
70 | callWhenActivatedHandler(false); |
71 | |
72 | auto taken = allWorkers().take(identifier()); |
73 | ASSERT_UNUSED(taken, taken == this); |
74 | } |
75 | |
76 | ServiceWorkerContextData SWServerWorker::contextData() const |
77 | { |
78 | auto* registration = m_server.getRegistration(m_registrationKey); |
79 | ASSERT(registration); |
80 | |
81 | return { WTF::nullopt, registration->data(), m_data.identifier, m_script, m_contentSecurityPolicy, m_referrerPolicy, m_data.scriptURL, m_data.type, m_server.sessionID(), false, m_scriptResourceMap }; |
82 | } |
83 | |
84 | void SWServerWorker::terminate() |
85 | { |
86 | if (isRunning()) |
87 | m_server.terminateWorker(*this); |
88 | } |
89 | |
90 | const ClientOrigin& SWServerWorker::origin() const |
91 | { |
92 | if (!m_origin) |
93 | m_origin = ClientOrigin { m_registrationKey.topOrigin(), SecurityOriginData::fromURL(m_data.scriptURL) }; |
94 | |
95 | return *m_origin; |
96 | } |
97 | |
98 | SWServerToContextConnection* SWServerWorker::contextConnection() |
99 | { |
100 | return SWServerToContextConnection::connectionForRegistrableDomain(registrableDomain()); |
101 | } |
102 | |
103 | void SWServerWorker::scriptContextFailedToStart(const Optional<ServiceWorkerJobDataIdentifier>& jobDataIdentifier, const String& message) |
104 | { |
105 | m_server.scriptContextFailedToStart(jobDataIdentifier, *this, message); |
106 | } |
107 | |
108 | void SWServerWorker::scriptContextStarted(const Optional<ServiceWorkerJobDataIdentifier>& jobDataIdentifier) |
109 | { |
110 | m_server.scriptContextStarted(jobDataIdentifier, *this); |
111 | } |
112 | |
113 | void SWServerWorker::didFinishInstall(const 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 | 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, ServiceWorkerClientsMatchAllCallback&& callback) |
134 | { |
135 | return m_server.matchAll(*this, options, WTFMove(callback)); |
136 | } |
137 | |
138 | String SWServerWorker::userAgent() const |
139 | { |
140 | return m_server.serviceWorkerClientUserAgent(origin()); |
141 | } |
142 | |
143 | void SWServerWorker::claim() |
144 | { |
145 | return m_server.claim(*this); |
146 | } |
147 | |
148 | void SWServerWorker::setScriptResource(URL&& url, ServiceWorkerContextData::ImportedScript&& script) |
149 | { |
150 | m_scriptResourceMap.set(WTFMove(url), WTFMove(script)); |
151 | } |
152 | |
153 | void SWServerWorker::skipWaiting() |
154 | { |
155 | m_isSkipWaitingFlagSet = true; |
156 | |
157 | auto* registration = m_server.getRegistration(m_registrationKey); |
158 | ASSERT(registration || isTerminating()); |
159 | if (registration) |
160 | registration->tryActivate(); |
161 | } |
162 | |
163 | void SWServerWorker::setHasPendingEvents(bool hasPendingEvents) |
164 | { |
165 | if (m_hasPendingEvents == hasPendingEvents) |
166 | return; |
167 | |
168 | m_hasPendingEvents = hasPendingEvents; |
169 | if (m_hasPendingEvents) |
170 | return; |
171 | |
172 | // Do tryClear/tryActivate, as per https://w3c.github.io/ServiceWorker/#wait-until-method. |
173 | auto* registration = m_server.getRegistration(m_registrationKey); |
174 | if (!registration) |
175 | return; |
176 | |
177 | if (registration->isUninstalling() && registration->tryClear()) |
178 | return; |
179 | registration->tryActivate(); |
180 | } |
181 | |
182 | void SWServerWorker::whenActivated(WTF::Function<void(bool)>&& handler) |
183 | { |
184 | if (state() == ServiceWorkerState::Activated) { |
185 | handler(true); |
186 | return; |
187 | } |
188 | m_whenActivatedHandlers.append(WTFMove(handler)); |
189 | } |
190 | |
191 | void SWServerWorker::setState(ServiceWorkerState state) |
192 | { |
193 | if (state == ServiceWorkerState::Redundant) |
194 | terminate(); |
195 | |
196 | m_data.state = state; |
197 | |
198 | auto* registration = m_server.getRegistration(m_registrationKey); |
199 | ASSERT(registration || state == ServiceWorkerState::Redundant); |
200 | if (registration) { |
201 | registration->forEachConnection([&](auto& connection) { |
202 | connection.updateWorkerStateInClient(this->identifier(), state); |
203 | }); |
204 | } |
205 | |
206 | if (state == ServiceWorkerState::Activated || state == ServiceWorkerState::Redundant) |
207 | callWhenActivatedHandler(state == ServiceWorkerState::Activated); |
208 | } |
209 | |
210 | void SWServerWorker::callWhenActivatedHandler(bool success) |
211 | { |
212 | auto whenActivatedHandlers = WTFMove(m_whenActivatedHandlers); |
213 | for (auto& handler : whenActivatedHandlers) |
214 | handler(success); |
215 | } |
216 | |
217 | void SWServerWorker::setState(State state) |
218 | { |
219 | ASSERT(state != State::Running || m_server.getRegistration(m_registrationKey)); |
220 | m_state = state; |
221 | } |
222 | |
223 | } // namespace WebCore |
224 | |
225 | #endif // ENABLE(SERVICE_WORKER) |
226 | |