e59083ca4953a6b326a4fd9987bfc7acf7fa417d
[WebKit-https.git] / Source / WebKit / WebProcess / Storage / WebSWContextManagerConnection.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 "WebSWContextManagerConnection.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 "NetworkProcessMessages.h"
36 #include "ServiceWorkerFetchTaskMessages.h"
37 #include "WebCacheStorageProvider.h"
38 #include "WebCoreArgumentCoders.h"
39 #include "WebDatabaseProvider.h"
40 #include "WebDocumentLoader.h"
41 #include "WebFrameLoaderClient.h"
42 #include "WebPreferencesKeys.h"
43 #include "WebPreferencesStore.h"
44 #include "WebProcess.h"
45 #include "WebProcessPoolMessages.h"
46 #include "WebSWServerToContextConnectionMessages.h"
47 #include "WebServiceWorkerFetchTaskClient.h"
48 #include "WebSocketProvider.h"
49 #include <WebCore/EditorClient.h>
50 #include <WebCore/EmptyClients.h>
51 #include <WebCore/LibWebRTCProvider.h>
52 #include <WebCore/MessageWithMessagePorts.h>
53 #include <WebCore/PageConfiguration.h>
54 #include <WebCore/RuntimeEnabledFeatures.h>
55 #include <WebCore/SerializedScriptValue.h>
56 #include <WebCore/ServiceWorkerClientData.h>
57 #include <WebCore/ServiceWorkerClientIdentifier.h>
58 #include <WebCore/ServiceWorkerClientQueryOptions.h>
59 #include <WebCore/ServiceWorkerJobDataIdentifier.h>
60 #include <WebCore/UserAgent.h>
61 #include <pal/SessionID.h>
62 #include <wtf/ProcessID.h>
63
64 #if USE(QUICK_LOOK)
65 #include <WebCore/PreviewLoaderClient.h>
66 #endif
67
68 namespace WebKit {
69 using namespace PAL;
70 using namespace WebCore;
71
72 static const Seconds asyncWorkerTerminationTimeout { 10_s };
73 static const Seconds syncWorkerTerminationTimeout { 100_ms }; // Only used by layout tests.
74
75 ServiceWorkerFrameLoaderClient::ServiceWorkerFrameLoaderClient(WebSWContextManagerConnection& connection, SessionID sessionID, WebPageProxyIdentifier webPageProxyID, PageIdentifier pageID, FrameIdentifier frameID, const String& userAgent)
76     : m_connection(connection)
77     , m_sessionID(sessionID)
78     , m_webPageProxyID(webPageProxyID)
79     , m_pageID(pageID)
80     , m_frameID(frameID)
81     , m_userAgent(userAgent)
82 {
83 }
84
85 Ref<DocumentLoader> ServiceWorkerFrameLoaderClient::createDocumentLoader(const ResourceRequest& request, const SubstituteData& substituteData)
86 {
87     return WebDocumentLoader::create(request, substituteData);
88 }
89
90 WebSWContextManagerConnection::WebSWContextManagerConnection(Ref<IPC::Connection>&& connection, WebCore::RegistrableDomain&& registrableDomain, PAL::SessionID sessionID, uint64_t pageGroupID, WebPageProxyIdentifier webPageProxyID, PageIdentifier pageID, const WebPreferencesStore& store)
91     : m_connectionToNetworkProcess(WTFMove(connection))
92     , m_registrableDomain(WTFMove(registrableDomain))
93     , m_pageGroupID(pageGroupID)
94     , m_webPageProxyID(webPageProxyID)
95     , m_pageID(pageID)
96 #if PLATFORM(COCOA)
97     , m_userAgent(standardUserAgentWithApplicationName({ }))
98 #else
99     , m_userAgent(standardUserAgent())
100 #endif
101 {
102     updatePreferencesStore(store);
103     m_connectionToNetworkProcess->send(Messages::NetworkConnectionToWebProcess::EstablishSWContextConnection { m_registrableDomain }, 0);
104 }
105
106 WebSWContextManagerConnection::~WebSWContextManagerConnection() = default;
107
108 void WebSWContextManagerConnection::updatePreferencesStore(const WebPreferencesStore& store)
109 {
110     RuntimeEnabledFeatures::sharedFeatures().setServiceWorkerEnabled(true);
111     RuntimeEnabledFeatures::sharedFeatures().setCacheAPIEnabled(store.getBoolValueForKey(WebPreferencesKey::cacheAPIEnabledKey()));
112     RuntimeEnabledFeatures::sharedFeatures().setFetchAPIEnabled(store.getBoolValueForKey(WebPreferencesKey::fetchAPIEnabledKey()));
113     RuntimeEnabledFeatures::sharedFeatures().setUserTimingEnabled(store.getBoolValueForKey(WebPreferencesKey::userTimingEnabledKey()));
114     RuntimeEnabledFeatures::sharedFeatures().setResourceTimingEnabled(store.getBoolValueForKey(WebPreferencesKey::resourceTimingEnabledKey()));
115     RuntimeEnabledFeatures::sharedFeatures().setFetchAPIKeepAliveEnabled(store.getBoolValueForKey(WebPreferencesKey::fetchAPIKeepAliveEnabledKey()));
116     RuntimeEnabledFeatures::sharedFeatures().setRestrictedHTTPResponseAccess(store.getBoolValueForKey(WebPreferencesKey::restrictedHTTPResponseAccessKey()));
117     RuntimeEnabledFeatures::sharedFeatures().setServerTimingEnabled(store.getBoolValueForKey(WebPreferencesKey::serverTimingEnabledKey()));
118     RuntimeEnabledFeatures::sharedFeatures().setIsSecureContextAttributeEnabled(store.getBoolValueForKey(WebPreferencesKey::isSecureContextAttributeEnabledKey()));
119     RuntimeEnabledFeatures::sharedFeatures().setSecureContextChecksEnabled(store.getBoolValueForKey(WebPreferencesKey::secureContextChecksEnabledKey()));
120
121     m_storageBlockingPolicy = static_cast<SecurityOrigin::StorageBlockingPolicy>(store.getUInt32ValueForKey(WebPreferencesKey::storageBlockingPolicyKey()));
122 }
123
124 void WebSWContextManagerConnection::installServiceWorker(const ServiceWorkerContextData& data, SessionID sessionID, String&& userAgent)
125 {
126     LOG(ServiceWorker, "WebSWContextManagerConnection::installServiceWorker for worker %s", data.serviceWorkerIdentifier.loggingString().utf8().data());
127
128     auto pageConfiguration = pageConfigurationWithEmptyClients(WebProcess::singleton().sessionID());
129
130 #if ENABLE(INDEXED_DATABASE)
131     pageConfiguration.databaseProvider = WebDatabaseProvider::getOrCreate(m_pageGroupID);
132 #endif
133     pageConfiguration.socketProvider = WebSocketProvider::create();
134
135     auto effectiveUserAgent =  WTFMove(userAgent);
136     if (effectiveUserAgent.isNull())
137         effectiveUserAgent = m_userAgent;
138
139     // FIXME: This method should be moved directly to WebCore::SWContextManager::Connection
140     // If it weren't for ServiceWorkerFrameLoaderClient's dependence on WebDocumentLoader, this could already happen.
141     // FIXME: Weird to pass m_previousServiceWorkerID as a FrameIdentifier.
142     auto frameLoaderClient = makeUnique<ServiceWorkerFrameLoaderClient>(*this, sessionID, m_webPageProxyID, m_pageID, frameIdentifierFromID(++m_previousServiceWorkerID), effectiveUserAgent);
143     pageConfiguration.loaderClientForMainFrame = frameLoaderClient.get();
144     m_loaders.add(WTFMove(frameLoaderClient));
145
146     auto serviceWorkerThreadProxy = ServiceWorkerThreadProxy::create(WTFMove(pageConfiguration), data, sessionID, WTFMove(effectiveUserAgent), WebProcess::singleton().cacheStorageProvider(), m_storageBlockingPolicy);
147     SWContextManager::singleton().registerServiceWorkerThreadForInstall(WTFMove(serviceWorkerThreadProxy));
148
149     LOG(ServiceWorker, "Context process PID: %i created worker thread\n", getCurrentProcessID());
150 }
151
152 void WebSWContextManagerConnection::setUserAgent(String&& userAgent)
153 {
154     m_userAgent = WTFMove(userAgent);
155 }
156
157 void WebSWContextManagerConnection::removeFrameLoaderClient(ServiceWorkerFrameLoaderClient& client)
158 {
159     auto result = m_loaders.remove(&client);
160     ASSERT_UNUSED(result, result);
161 }
162
163 void WebSWContextManagerConnection::serviceWorkerStarted(Optional<ServiceWorkerJobDataIdentifier> jobDataIdentifier, ServiceWorkerIdentifier serviceWorkerIdentifier, bool doesHandleFetch)
164 {
165     m_connectionToNetworkProcess->send(Messages::WebSWServerToContextConnection::ScriptContextStarted { jobDataIdentifier, serviceWorkerIdentifier, doesHandleFetch }, 0);
166 }
167
168 void WebSWContextManagerConnection::serviceWorkerFailedToStart(Optional<ServiceWorkerJobDataIdentifier> jobDataIdentifier, ServiceWorkerIdentifier serviceWorkerIdentifier, const String& exceptionMessage)
169 {
170     m_connectionToNetworkProcess->send(Messages::WebSWServerToContextConnection::ScriptContextFailedToStart { jobDataIdentifier, serviceWorkerIdentifier, exceptionMessage }, 0);
171 }
172
173 static inline bool isValidFetch(const ResourceRequest& request, const FetchOptions& options, const URL& serviceWorkerURL, const String& referrer)
174 {
175     // For exotic service workers, do not enforce checks.
176     if (!serviceWorkerURL.protocolIsInHTTPFamily())
177         return true;
178
179     if (options.mode == FetchOptions::Mode::Navigate) {
180         if (!protocolHostAndPortAreEqual(request.url(), serviceWorkerURL)) {
181             RELEASE_LOG_ERROR(ServiceWorker, "Should not intercept a navigation load that is not same-origin as the service worker URL");
182             RELEASE_ASSERT_WITH_MESSAGE(request.url().host() == serviceWorkerURL.host(), "Hosts do not match");
183             RELEASE_ASSERT_WITH_MESSAGE(request.url().protocol() == serviceWorkerURL.protocol(), "Protocols do not match");
184             RELEASE_ASSERT_WITH_MESSAGE(request.url().port() == serviceWorkerURL.port(), "Ports do not match");
185             return false;
186         }
187         return true;
188     }
189
190     String origin = request.httpOrigin();
191     URL url { URL(), origin.isEmpty() ? referrer : origin };
192     if (url.protocolIsInHTTPFamily() && !protocolHostAndPortAreEqual(url, serviceWorkerURL)) {
193         RELEASE_LOG_ERROR(ServiceWorker, "Should not intercept a non navigation load that is not originating from a same-origin context as the service worker URL");
194         ASSERT(url.host() == serviceWorkerURL.host());
195         ASSERT(url.protocol() == serviceWorkerURL.protocol());
196         ASSERT(url.port() == serviceWorkerURL.port());
197         return false;
198     }
199     return true;
200 }
201
202 void WebSWContextManagerConnection::cancelFetch(SWServerConnectionIdentifier serverConnectionIdentifier, ServiceWorkerIdentifier serviceWorkerIdentifier, FetchIdentifier fetchIdentifier)
203 {
204     if (auto* serviceWorkerThreadProxy = SWContextManager::singleton().serviceWorkerThreadProxy(serviceWorkerIdentifier))
205         serviceWorkerThreadProxy->cancelFetch(serverConnectionIdentifier, fetchIdentifier);
206 }
207
208 void WebSWContextManagerConnection::continueDidReceiveFetchResponse(SWServerConnectionIdentifier serverConnectionIdentifier, ServiceWorkerIdentifier serviceWorkerIdentifier, FetchIdentifier fetchIdentifier)
209 {
210     if (auto* serviceWorkerThreadProxy = SWContextManager::singleton().serviceWorkerThreadProxy(serviceWorkerIdentifier))
211         serviceWorkerThreadProxy->continueDidReceiveFetchResponse(serverConnectionIdentifier, fetchIdentifier);
212 }
213
214 void WebSWContextManagerConnection::startFetch(SWServerConnectionIdentifier serverConnectionIdentifier, ServiceWorkerIdentifier serviceWorkerIdentifier, FetchIdentifier fetchIdentifier, ResourceRequest&& request, FetchOptions&& options, IPC::FormDataReference&& formData, String&& referrer)
215 {
216     auto* serviceWorkerThreadProxy = SWContextManager::singleton().serviceWorkerThreadProxy(serviceWorkerIdentifier);
217     if (!serviceWorkerThreadProxy) {
218         m_connectionToNetworkProcess->send(Messages::ServiceWorkerFetchTask::DidNotHandle { }, fetchIdentifier);
219         return;
220     }
221
222     if (!isValidFetch(request, options, serviceWorkerThreadProxy->scriptURL(), referrer)) {
223         m_connectionToNetworkProcess->send(Messages::ServiceWorkerFetchTask::DidNotHandle { }, fetchIdentifier);
224         return;
225     }
226
227     auto client = WebServiceWorkerFetchTaskClient::create(m_connectionToNetworkProcess.copyRef(), serviceWorkerIdentifier, serverConnectionIdentifier, fetchIdentifier, request.requester() == ResourceRequest::Requester::Main);
228     Optional<ServiceWorkerClientIdentifier> clientId;
229     if (options.clientIdentifier)
230         clientId = ServiceWorkerClientIdentifier { serverConnectionIdentifier, options.clientIdentifier.value() };
231
232     request.setHTTPBody(formData.takeData());
233     serviceWorkerThreadProxy->startFetch(serverConnectionIdentifier, fetchIdentifier, WTFMove(client), WTFMove(clientId), WTFMove(request), WTFMove(referrer), WTFMove(options));
234 }
235
236 void WebSWContextManagerConnection::postMessageToServiceWorker(ServiceWorkerIdentifier destinationIdentifier, MessageWithMessagePorts&& message, ServiceWorkerOrClientData&& sourceData)
237 {
238     SWContextManager::singleton().postMessageToServiceWorker(destinationIdentifier, WTFMove(message), WTFMove(sourceData));
239 }
240
241 void WebSWContextManagerConnection::fireInstallEvent(ServiceWorkerIdentifier identifier)
242 {
243     SWContextManager::singleton().fireInstallEvent(identifier);
244 }
245
246 void WebSWContextManagerConnection::fireActivateEvent(ServiceWorkerIdentifier identifier)
247 {
248     SWContextManager::singleton().fireActivateEvent(identifier);
249 }
250
251 void WebSWContextManagerConnection::softUpdate(WebCore::ServiceWorkerIdentifier identifier)
252 {
253     SWContextManager::singleton().softUpdate(identifier);
254 }
255
256 void WebSWContextManagerConnection::terminateWorker(ServiceWorkerIdentifier identifier)
257 {
258     SWContextManager::singleton().terminateWorker(identifier, asyncWorkerTerminationTimeout, nullptr);
259 }
260
261 void WebSWContextManagerConnection::syncTerminateWorker(ServiceWorkerIdentifier identifier, Messages::WebSWContextManagerConnection::SyncTerminateWorker::DelayedReply&& reply)
262 {
263     SWContextManager::singleton().terminateWorker(identifier, syncWorkerTerminationTimeout, WTFMove(reply));
264 }
265
266 void WebSWContextManagerConnection::postMessageToServiceWorkerClient(const ServiceWorkerClientIdentifier& destinationIdentifier, const MessageWithMessagePorts& message, ServiceWorkerIdentifier sourceIdentifier, const String& sourceOrigin)
267 {
268     m_connectionToNetworkProcess->send(Messages::WebSWServerToContextConnection::PostMessageToServiceWorkerClient(destinationIdentifier, message, sourceIdentifier, sourceOrigin), 0);
269 }
270
271 void WebSWContextManagerConnection::didFinishInstall(Optional<ServiceWorkerJobDataIdentifier> jobDataIdentifier, ServiceWorkerIdentifier serviceWorkerIdentifier, bool wasSuccessful)
272 {
273     m_connectionToNetworkProcess->send(Messages::WebSWServerToContextConnection::DidFinishInstall(jobDataIdentifier, serviceWorkerIdentifier, wasSuccessful), 0);
274 }
275
276 void WebSWContextManagerConnection::didFinishActivation(ServiceWorkerIdentifier serviceWorkerIdentifier)
277 {
278     m_connectionToNetworkProcess->send(Messages::WebSWServerToContextConnection::DidFinishActivation(serviceWorkerIdentifier), 0);
279 }
280
281 void WebSWContextManagerConnection::setServiceWorkerHasPendingEvents(ServiceWorkerIdentifier serviceWorkerIdentifier, bool hasPendingEvents)
282 {
283     m_connectionToNetworkProcess->send(Messages::WebSWServerToContextConnection::SetServiceWorkerHasPendingEvents(serviceWorkerIdentifier, hasPendingEvents), 0);
284 }
285
286 void WebSWContextManagerConnection::skipWaiting(ServiceWorkerIdentifier serviceWorkerIdentifier, WTF::Function<void()>&& callback)
287 {
288     auto callbackID = ++m_previousRequestIdentifier;
289     m_skipWaitingRequests.add(callbackID, WTFMove(callback));
290     m_connectionToNetworkProcess->send(Messages::WebSWServerToContextConnection::SkipWaiting(serviceWorkerIdentifier, callbackID), 0);
291 }
292
293 void WebSWContextManagerConnection::setScriptResource(ServiceWorkerIdentifier serviceWorkerIdentifier, const URL& url, const ServiceWorkerContextData::ImportedScript& script)
294 {
295     m_connectionToNetworkProcess->send(Messages::WebSWServerToContextConnection::SetScriptResource { serviceWorkerIdentifier, url, script.script, script.responseURL, script.mimeType }, 0);
296 }
297
298 void WebSWContextManagerConnection::workerTerminated(ServiceWorkerIdentifier serviceWorkerIdentifier)
299 {
300     m_connectionToNetworkProcess->send(Messages::WebSWServerToContextConnection::WorkerTerminated(serviceWorkerIdentifier), 0);
301 }
302
303 void WebSWContextManagerConnection::findClientByIdentifier(WebCore::ServiceWorkerIdentifier serviceWorkerIdentifier, ServiceWorkerClientIdentifier clientIdentifier, FindClientByIdentifierCallback&& callback)
304 {
305     auto requestIdentifier = ++m_previousRequestIdentifier;
306     m_findClientByIdentifierRequests.add(requestIdentifier, WTFMove(callback));
307     m_connectionToNetworkProcess->send(Messages::WebSWServerToContextConnection::FindClientByIdentifier { requestIdentifier, serviceWorkerIdentifier, clientIdentifier }, 0);
308 }
309
310 void WebSWContextManagerConnection::findClientByIdentifierCompleted(uint64_t requestIdentifier, Optional<ServiceWorkerClientData>&& clientData, bool hasSecurityError)
311 {
312     if (auto callback = m_findClientByIdentifierRequests.take(requestIdentifier)) {
313         if (hasSecurityError) {
314             callback(Exception { SecurityError });
315             return;
316         }
317         callback(WTFMove(clientData));
318     }
319 }
320
321 void WebSWContextManagerConnection::matchAll(WebCore::ServiceWorkerIdentifier serviceWorkerIdentifier, const ServiceWorkerClientQueryOptions& options, ServiceWorkerClientsMatchAllCallback&& callback)
322 {
323     auto requestIdentifier = ++m_previousRequestIdentifier;
324     m_matchAllRequests.add(requestIdentifier, WTFMove(callback));
325     m_connectionToNetworkProcess->send(Messages::WebSWServerToContextConnection::MatchAll { requestIdentifier, serviceWorkerIdentifier, options }, 0);
326 }
327
328 void WebSWContextManagerConnection::matchAllCompleted(uint64_t requestIdentifier, Vector<ServiceWorkerClientData>&& clientsData)
329 {
330     if (auto callback = m_matchAllRequests.take(requestIdentifier))
331         callback(WTFMove(clientsData));
332 }
333
334 void WebSWContextManagerConnection::claim(WebCore::ServiceWorkerIdentifier serviceWorkerIdentifier, CompletionHandler<void()>&& callback)
335 {
336     auto requestIdentifier = ++m_previousRequestIdentifier;
337     m_claimRequests.add(requestIdentifier, WTFMove(callback));
338     m_connectionToNetworkProcess->send(Messages::WebSWServerToContextConnection::Claim { requestIdentifier, serviceWorkerIdentifier }, 0);
339 }
340
341 void WebSWContextManagerConnection::claimCompleted(uint64_t claimRequestIdentifier)
342 {
343     if (auto callback = m_claimRequests.take(claimRequestIdentifier))
344         callback();
345 }
346
347 void WebSWContextManagerConnection::didFinishSkipWaiting(uint64_t callbackID)
348 {
349     if (auto callback = m_skipWaitingRequests.take(callbackID))
350         callback();
351 }
352
353 void WebSWContextManagerConnection::terminateProcess()
354 {
355     RELEASE_LOG(ServiceWorker, "Service worker process is exiting because it is no longer needed");
356     _exit(EXIT_SUCCESS);
357 }
358
359 void WebSWContextManagerConnection::setThrottleState(bool isThrottleable)
360 {
361     RELEASE_LOG(ServiceWorker, "Service worker throttleable state is set to %d", isThrottleable);
362     m_isThrottleable = isThrottleable;
363     WebProcess::singleton().setProcessSuppressionEnabled(isThrottleable);
364 }
365
366 bool WebSWContextManagerConnection::isThrottleable() const
367 {
368     return m_isThrottleable;
369 }
370
371 } // namespace WebCore
372
373 #endif // ENABLE(SERVICE_WORKER)