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