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 "WebSWClientConnection.h"
28
29#if ENABLE(SERVICE_WORKER)
30
31#include "DataReference.h"
32#include "FormDataReference.h"
33#include "Logging.h"
34#include "NetworkProcessConnection.h"
35#include "ServiceWorkerClientFetch.h"
36#include "WebCoreArgumentCoders.h"
37#include "WebProcess.h"
38#include "WebProcessPoolMessages.h"
39#include "WebSWOriginTable.h"
40#include "WebSWServerConnectionMessages.h"
41#include <WebCore/Document.h>
42#include <WebCore/SecurityOrigin.h>
43#include <WebCore/SerializedScriptValue.h>
44#include <WebCore/ServiceWorkerClientData.h>
45#include <WebCore/ServiceWorkerFetchResult.h>
46#include <WebCore/ServiceWorkerJobData.h>
47#include <WebCore/ServiceWorkerRegistrationData.h>
48#include <WebCore/ServiceWorkerRegistrationKey.h>
49
50namespace WebKit {
51using namespace PAL;
52using namespace WebCore;
53
54
55WebSWClientConnection::WebSWClientConnection(SessionID sessionID)
56 : m_sessionID(sessionID)
57 , m_swOriginTable(makeUniqueRef<WebSWOriginTable>())
58{
59 ASSERT(sessionID.isValid());
60 initializeConnectionIfNeeded();
61}
62
63WebSWClientConnection::~WebSWClientConnection()
64{
65 if (m_connection)
66 WebProcess::singleton().ensureNetworkProcessConnection().removeSWClientConnection(*this);
67}
68
69void WebSWClientConnection::initializeConnectionIfNeeded()
70{
71 if (m_connection)
72 return;
73
74 auto& networkProcessConnection = WebProcess::singleton().ensureNetworkProcessConnection();
75
76 m_connection = &networkProcessConnection.connection();
77 m_identifier = networkProcessConnection.initializeSWClientConnection(*this);
78
79 updateThrottleState();
80}
81
82template<typename U>
83void WebSWClientConnection::ensureConnectionAndSend(const U& message)
84{
85 initializeConnectionIfNeeded();
86 send(message);
87}
88
89void WebSWClientConnection::scheduleJobInServer(const ServiceWorkerJobData& jobData)
90{
91 ensureConnectionAndSend(Messages::WebSWServerConnection::ScheduleJobInServer(jobData));
92}
93
94void WebSWClientConnection::finishFetchingScriptInServer(const ServiceWorkerFetchResult& result)
95{
96 ensureConnectionAndSend(Messages::WebSWServerConnection::FinishFetchingScriptInServer(result));
97}
98
99void WebSWClientConnection::addServiceWorkerRegistrationInServer(ServiceWorkerRegistrationIdentifier identifier)
100{
101 ensureConnectionAndSend(Messages::WebSWServerConnection::AddServiceWorkerRegistrationInServer(identifier));
102}
103
104void WebSWClientConnection::removeServiceWorkerRegistrationInServer(ServiceWorkerRegistrationIdentifier identifier)
105{
106 ensureConnectionAndSend(Messages::WebSWServerConnection::RemoveServiceWorkerRegistrationInServer(identifier));
107}
108
109void WebSWClientConnection::postMessageToServiceWorker(ServiceWorkerIdentifier destinationIdentifier, MessageWithMessagePorts&& message, const ServiceWorkerOrClientIdentifier& sourceIdentifier)
110{
111 // FIXME: Temporarily pipe the SW postMessage messages via the UIProcess since this is where the MessagePort registry lives
112 // and this avoids races.
113 WebProcess::singleton().send(Messages::WebProcessPool::PostMessageToServiceWorker(destinationIdentifier, WTFMove(message), sourceIdentifier, serverConnectionIdentifier()), 0);
114}
115
116void WebSWClientConnection::registerServiceWorkerClient(const SecurityOrigin& topOrigin, const WebCore::ServiceWorkerClientData& data, const Optional<WebCore::ServiceWorkerRegistrationIdentifier>& controllingServiceWorkerRegistrationIdentifier, const String& userAgent)
117{
118 ensureConnectionAndSend(Messages::WebSWServerConnection::RegisterServiceWorkerClient { topOrigin.data(), data, controllingServiceWorkerRegistrationIdentifier, userAgent });
119}
120
121void WebSWClientConnection::unregisterServiceWorkerClient(DocumentIdentifier contextIdentifier)
122{
123 ensureConnectionAndSend(Messages::WebSWServerConnection::UnregisterServiceWorkerClient { ServiceWorkerClientIdentifier { serverConnectionIdentifier(), contextIdentifier } });
124}
125
126void WebSWClientConnection::didResolveRegistrationPromise(const ServiceWorkerRegistrationKey& key)
127{
128 ensureConnectionAndSend(Messages::WebSWServerConnection::DidResolveRegistrationPromise(key));
129}
130
131bool WebSWClientConnection::mayHaveServiceWorkerRegisteredForOrigin(const SecurityOriginData& origin) const
132{
133 if (!m_swOriginTable->isImported())
134 return true;
135
136 return m_swOriginTable->contains(origin);
137}
138
139void WebSWClientConnection::setSWOriginTableSharedMemory(const SharedMemory::Handle& handle)
140{
141 m_swOriginTable->setSharedMemory(handle);
142}
143
144void WebSWClientConnection::setSWOriginTableIsImported()
145{
146 m_swOriginTable->setIsImported();
147 while (!m_tasksPendingOriginImport.isEmpty())
148 m_tasksPendingOriginImport.takeFirst()();
149}
150
151void WebSWClientConnection::didMatchRegistration(uint64_t matchingRequest, Optional<ServiceWorkerRegistrationData>&& result)
152{
153 ASSERT(isMainThread());
154
155 if (auto completionHandler = m_ongoingMatchRegistrationTasks.take(matchingRequest))
156 completionHandler(WTFMove(result));
157}
158
159void WebSWClientConnection::didGetRegistrations(uint64_t matchingRequest, Vector<ServiceWorkerRegistrationData>&& registrations)
160{
161 ASSERT(isMainThread());
162
163 if (auto completionHandler = m_ongoingGetRegistrationsTasks.take(matchingRequest))
164 completionHandler(WTFMove(registrations));
165}
166
167void WebSWClientConnection::matchRegistration(SecurityOriginData&& topOrigin, const URL& clientURL, RegistrationCallback&& callback)
168{
169 ASSERT(isMainThread());
170
171 if (!mayHaveServiceWorkerRegisteredForOrigin(topOrigin)) {
172 callback(WTF::nullopt);
173 return;
174 }
175
176 runOrDelayTaskForImport([this, callback = WTFMove(callback), topOrigin = WTFMove(topOrigin), clientURL]() mutable {
177 uint64_t callbackID = ++m_previousCallbackIdentifier;
178 m_ongoingMatchRegistrationTasks.add(callbackID, WTFMove(callback));
179 ensureConnectionAndSend(Messages::WebSWServerConnection::MatchRegistration(callbackID, topOrigin, clientURL));
180 });
181}
182
183void WebSWClientConnection::runOrDelayTaskForImport(WTF::Function<void()>&& task)
184{
185 if (m_swOriginTable->isImported()) {
186 task();
187 return;
188 }
189 m_tasksPendingOriginImport.append(WTFMove(task));
190 initializeConnectionIfNeeded();
191}
192
193void WebSWClientConnection::whenRegistrationReady(const SecurityOrigin& topOrigin, const URL& clientURL, WhenRegistrationReadyCallback&& callback)
194{
195 uint64_t callbackID = ++m_previousCallbackIdentifier;
196 m_ongoingRegistrationReadyTasks.add(callbackID, WTFMove(callback));
197 ensureConnectionAndSend(Messages::WebSWServerConnection::WhenRegistrationReady(callbackID, topOrigin.data(), clientURL));
198}
199
200void WebSWClientConnection::registrationReady(uint64_t callbackID, WebCore::ServiceWorkerRegistrationData&& registrationData)
201{
202 ASSERT(registrationData.activeWorker);
203 if (auto callback = m_ongoingRegistrationReadyTasks.take(callbackID))
204 callback(WTFMove(registrationData));
205}
206
207void WebSWClientConnection::getRegistrations(SecurityOriginData&& topOrigin, const URL& clientURL, GetRegistrationsCallback&& callback)
208{
209 ASSERT(isMainThread());
210
211 if (!mayHaveServiceWorkerRegisteredForOrigin(topOrigin)) {
212 callback({ });
213 return;
214 }
215
216 runOrDelayTaskForImport([this, callback = WTFMove(callback), topOrigin = WTFMove(topOrigin), clientURL]() mutable {
217 uint64_t callbackID = ++m_previousCallbackIdentifier;
218 m_ongoingGetRegistrationsTasks.add(callbackID, WTFMove(callback));
219 ensureConnectionAndSend(Messages::WebSWServerConnection::GetRegistrations(callbackID, topOrigin, clientURL));
220 });
221}
222
223void WebSWClientConnection::startFetch(FetchIdentifier fetchIdentifier, ServiceWorkerRegistrationIdentifier serviceWorkerRegistrationIdentifier, const ResourceRequest& request, const FetchOptions& options, const String& referrer)
224{
225 ensureConnectionAndSend(Messages::WebSWServerConnection::StartFetch { serviceWorkerRegistrationIdentifier, fetchIdentifier, request, options, IPC::FormDataReference { request.httpBody() }, referrer });
226}
227
228void WebSWClientConnection::cancelFetch(FetchIdentifier fetchIdentifier, ServiceWorkerRegistrationIdentifier serviceWorkerRegistrationIdentifier)
229{
230 ensureConnectionAndSend(Messages::WebSWServerConnection::CancelFetch { serviceWorkerRegistrationIdentifier, fetchIdentifier });
231}
232
233void WebSWClientConnection::continueDidReceiveFetchResponse(FetchIdentifier fetchIdentifier, ServiceWorkerRegistrationIdentifier serviceWorkerRegistrationIdentifier)
234{
235 ensureConnectionAndSend(Messages::WebSWServerConnection::ContinueDidReceiveFetchResponse { serviceWorkerRegistrationIdentifier, fetchIdentifier });
236}
237
238void WebSWClientConnection::connectionToServerLost()
239{
240 m_connection = nullptr;
241
242 auto registrationTasks = WTFMove(m_ongoingMatchRegistrationTasks);
243 for (auto& callback : registrationTasks.values())
244 callback(WTF::nullopt);
245
246 auto getRegistrationTasks = WTFMove(m_ongoingGetRegistrationsTasks);
247 for (auto& callback : getRegistrationTasks.values())
248 callback({ });
249
250 clearPendingJobs();
251}
252
253void WebSWClientConnection::syncTerminateWorker(ServiceWorkerIdentifier identifier)
254{
255 initializeConnectionIfNeeded();
256
257 sendSync(Messages::WebSWServerConnection::SyncTerminateWorkerFromClient(identifier), Messages::WebSWServerConnection::SyncTerminateWorkerFromClient::Reply());
258}
259
260WebCore::SWServerConnectionIdentifier WebSWClientConnection::serverConnectionIdentifier() const
261{
262 const_cast<WebSWClientConnection*>(this)->initializeConnectionIfNeeded();
263 return m_identifier;
264}
265
266void WebSWClientConnection::updateThrottleState()
267{
268 m_isThrottleable = WebProcess::singleton().areAllPagesThrottleable();
269 ensureConnectionAndSend(Messages::WebSWServerConnection::SetThrottleState { m_isThrottleable });
270}
271
272void WebSWClientConnection::storeRegistrationsOnDiskForTesting(CompletionHandler<void()>&& callback)
273{
274 initializeConnectionIfNeeded();
275 sendWithAsyncReply(Messages::WebSWServerConnection::StoreRegistrationsOnDisk { }, WTFMove(callback));
276}
277
278} // namespace WebKit
279
280#endif // ENABLE(SERVICE_WORKER)
281