Service Worker Fetch events should time out.
[WebKit-https.git] / Source / WebKit / NetworkProcess / ServiceWorker / WebSWServerConnection.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 "WebSWServerConnection.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 "NetworkProcess.h"
36 #include "ServiceWorkerClientFetchMessages.h"
37 #include "WebCoreArgumentCoders.h"
38 #include "WebProcess.h"
39 #include "WebProcessMessages.h"
40 #include "WebSWClientConnectionMessages.h"
41 #include "WebSWContextManagerConnectionMessages.h"
42 #include "WebSWServerConnectionMessages.h"
43 #include "WebSWServerToContextConnection.h"
44 #include <WebCore/DocumentIdentifier.h>
45 #include <WebCore/ExceptionData.h>
46 #include <WebCore/NotImplemented.h>
47 #include <WebCore/SWServerRegistration.h>
48 #include <WebCore/SecurityOrigin.h>
49 #include <WebCore/ServiceWorkerClientData.h>
50 #include <WebCore/ServiceWorkerClientIdentifier.h>
51 #include <WebCore/ServiceWorkerContextData.h>
52 #include <WebCore/ServiceWorkerJobData.h>
53 #include <WebCore/ServiceWorkerUpdateViaCache.h>
54 #include <wtf/Algorithms.h>
55 #include <wtf/MainThread.h>
56
57 namespace WebKit {
58 using namespace PAL;
59 using namespace WebCore;
60
61 #define SWSERVERCONNECTION_RELEASE_LOG_IF_ALLOWED(fmt, ...) RELEASE_LOG_IF(sessionID().isAlwaysOnLoggingAllowed(), ServiceWorker, "%p - WebSWServerConnection::" fmt, this, ##__VA_ARGS__)
62 #define SWSERVERCONNECTION_RELEASE_LOG_ERROR_IF_ALLOWED(fmt, ...) RELEASE_LOG_ERROR_IF(sessionID().isAlwaysOnLoggingAllowed(), ServiceWorker, "%p - WebSWServerConnection::" fmt, this, ##__VA_ARGS__)
63
64 WebSWServerConnection::WebSWServerConnection(NetworkProcess& networkProcess, SWServer& server, IPC::Connection& connection, ProcessIdentifier processIdentifier)
65     : SWServer::Connection(server, processIdentifier)
66     , m_contentConnection(connection)
67     , m_networkProcess(networkProcess)
68 {
69     networkProcess.registerSWServerConnection(*this);
70 }
71
72 WebSWServerConnection::~WebSWServerConnection()
73 {
74     m_networkProcess->unregisterSWServerConnection(*this);
75     for (const auto& keyValue : m_clientOrigins)
76         server().unregisterServiceWorkerClient(keyValue.value, keyValue.key);
77 }
78
79 void WebSWServerConnection::rejectJobInClient(ServiceWorkerJobIdentifier jobIdentifier, const ExceptionData& exceptionData)
80 {
81     send(Messages::WebSWClientConnection::JobRejectedInServer(jobIdentifier, exceptionData));
82 }
83
84 void WebSWServerConnection::resolveRegistrationJobInClient(ServiceWorkerJobIdentifier jobIdentifier, const ServiceWorkerRegistrationData& registrationData, ShouldNotifyWhenResolved shouldNotifyWhenResolved)
85 {
86     send(Messages::WebSWClientConnection::RegistrationJobResolvedInServer(jobIdentifier, registrationData, shouldNotifyWhenResolved));
87 }
88
89 void WebSWServerConnection::resolveUnregistrationJobInClient(ServiceWorkerJobIdentifier jobIdentifier, const ServiceWorkerRegistrationKey& registrationKey, bool unregistrationResult)
90 {
91     send(Messages::WebSWClientConnection::UnregistrationJobResolvedInServer(jobIdentifier, unregistrationResult));
92 }
93
94 void WebSWServerConnection::startScriptFetchInClient(ServiceWorkerJobIdentifier jobIdentifier, const ServiceWorkerRegistrationKey& registrationKey, FetchOptions::Cache cachePolicy)
95 {
96     send(Messages::WebSWClientConnection::StartScriptFetchForServer(jobIdentifier, registrationKey, cachePolicy));
97 }
98
99 void WebSWServerConnection::updateRegistrationStateInClient(ServiceWorkerRegistrationIdentifier identifier, ServiceWorkerRegistrationState state, const Optional<ServiceWorkerData>& serviceWorkerData)
100 {
101     send(Messages::WebSWClientConnection::UpdateRegistrationState(identifier, state, serviceWorkerData));
102 }
103
104 void WebSWServerConnection::fireUpdateFoundEvent(ServiceWorkerRegistrationIdentifier identifier)
105 {
106     send(Messages::WebSWClientConnection::FireUpdateFoundEvent(identifier));
107 }
108
109 void WebSWServerConnection::setRegistrationLastUpdateTime(ServiceWorkerRegistrationIdentifier identifier, WallTime lastUpdateTime)
110 {
111     send(Messages::WebSWClientConnection::SetRegistrationLastUpdateTime(identifier, lastUpdateTime));
112 }
113
114 void WebSWServerConnection::setRegistrationUpdateViaCache(ServiceWorkerRegistrationIdentifier identifier, ServiceWorkerUpdateViaCache updateViaCache)
115 {
116     send(Messages::WebSWClientConnection::SetRegistrationUpdateViaCache(identifier, updateViaCache));
117 }
118
119 void WebSWServerConnection::notifyClientsOfControllerChange(const HashSet<DocumentIdentifier>& contextIdentifiers, const ServiceWorkerData& newController)
120 {
121     send(Messages::WebSWClientConnection::NotifyClientsOfControllerChange(contextIdentifiers, newController));
122 }
123
124 void WebSWServerConnection::updateWorkerStateInClient(ServiceWorkerIdentifier worker, ServiceWorkerState state)
125 {
126     send(Messages::WebSWClientConnection::UpdateWorkerState(worker, state));
127 }
128
129 void WebSWServerConnection::cancelFetch(ServiceWorkerRegistrationIdentifier serviceWorkerRegistrationIdentifier, FetchIdentifier fetchIdentifier)
130 {
131     SWSERVERCONNECTION_RELEASE_LOG_IF_ALLOWED("cancelFetch: %s", fetchIdentifier.loggingString().utf8().data());
132     auto* worker = server().activeWorkerFromRegistrationID(serviceWorkerRegistrationIdentifier);
133     if (!worker || !worker->isRunning())
134         return;
135
136     auto serviceWorkerIdentifier = worker->identifier();
137     server().runServiceWorkerIfNecessary(serviceWorkerIdentifier, [weakThis = makeWeakPtr(this), this, serviceWorkerIdentifier, fetchIdentifier](auto* contextConnection) mutable {
138         if (weakThis && contextConnection)
139             static_cast<WebSWServerToContextConnection&>(*contextConnection).cancelFetch(this->identifier(), fetchIdentifier, serviceWorkerIdentifier);
140     });
141 }
142
143 void WebSWServerConnection::continueDidReceiveFetchResponse(ServiceWorkerRegistrationIdentifier serviceWorkerRegistrationIdentifier, FetchIdentifier fetchIdentifier)
144 {
145     auto* worker = server().activeWorkerFromRegistrationID(serviceWorkerRegistrationIdentifier);
146     if (!worker || !worker->isRunning())
147         return;
148
149     auto serviceWorkerIdentifier = worker->identifier();
150     server().runServiceWorkerIfNecessary(serviceWorkerIdentifier, [weakThis = makeWeakPtr(this), this, serviceWorkerIdentifier, fetchIdentifier](auto* contextConnection) mutable {
151         if (weakThis && contextConnection)
152             static_cast<WebSWServerToContextConnection&>(*contextConnection).continueDidReceiveFetchResponse(this->identifier(), fetchIdentifier, serviceWorkerIdentifier);
153     });
154 }
155
156 void WebSWServerConnection::startFetch(ServiceWorkerRegistrationIdentifier serviceWorkerRegistrationIdentifier, FetchIdentifier fetchIdentifier, ResourceRequest&& request, FetchOptions&& options, IPC::FormDataReference&& formData, String&& referrer)
157 {
158     auto* worker = server().activeWorkerFromRegistrationID(serviceWorkerRegistrationIdentifier);
159     if (!worker) {
160         SWSERVERCONNECTION_RELEASE_LOG_ERROR_IF_ALLOWED("startFetch: fetchIdentifier: %s -> DidNotHandle because no active worker", fetchIdentifier.loggingString().utf8().data());
161         m_contentConnection->send(Messages::ServiceWorkerClientFetch::DidNotHandle { }, fetchIdentifier);
162         return;
163     }
164     auto serviceWorkerIdentifier = worker->identifier();
165
166     auto runServerWorkerAndStartFetch = [weakThis = makeWeakPtr(this), this, fetchIdentifier, serviceWorkerIdentifier, request = WTFMove(request), options = WTFMove(options), formData = WTFMove(formData), referrer = WTFMove(referrer)](bool success) mutable {
167         if (!weakThis)
168             return;
169
170         if (!success) {
171             SWSERVERCONNECTION_RELEASE_LOG_ERROR_IF_ALLOWED("startFetch: fetchIdentifier: %s DidNotHandle because worker did not become activated", fetchIdentifier.loggingString().utf8().data());
172             m_contentConnection->send(Messages::ServiceWorkerClientFetch::DidNotHandle { }, fetchIdentifier);
173             return;
174         }
175
176         auto* worker = server().workerByID(serviceWorkerIdentifier);
177         if (!worker || worker->hasTimedOutAnyFetchTasks()) {
178             m_contentConnection->send(Messages::ServiceWorkerClientFetch::DidNotHandle { }, fetchIdentifier);
179             return;
180         }
181
182         if (!worker->contextConnection())
183             server().createContextConnection(worker->registrableDomain());
184
185         server().runServiceWorkerIfNecessary(serviceWorkerIdentifier, [weakThis = WTFMove(weakThis), this, fetchIdentifier, serviceWorkerIdentifier, request = WTFMove(request), options = WTFMove(options), formData = WTFMove(formData), referrer = WTFMove(referrer), shouldSkipFetchEvent = worker->shouldSkipFetchEvent()](auto* contextConnection) {
186             if (!weakThis)
187                 return;
188
189             if (contextConnection) {
190                 SWSERVERCONNECTION_RELEASE_LOG_IF_ALLOWED("startFetch: Starting fetch %s via service worker %s", fetchIdentifier.loggingString().utf8().data(), serviceWorkerIdentifier.loggingString().utf8().data());
191                 static_cast<WebSWServerToContextConnection&>(*contextConnection).startFetch(sessionID(), *this, fetchIdentifier, serviceWorkerIdentifier, request, options, formData, referrer);
192             } else {
193                 SWSERVERCONNECTION_RELEASE_LOG_ERROR_IF_ALLOWED("startFetch: fetchIdentifier: %s DidNotHandle because failed to run service worker, or service worker has had timed out fetch tasks", fetchIdentifier.loggingString().utf8().data());
194                 m_contentConnection->send(Messages::ServiceWorkerClientFetch::DidNotHandle { }, fetchIdentifier);
195             }
196         });
197     };
198
199     if (worker->shouldSkipFetchEvent()) {
200         m_contentConnection->send(Messages::ServiceWorkerClientFetch::DidNotHandle { }, fetchIdentifier);
201         auto* registration = server().getRegistration(worker->registrationKey());
202         if (registration && registration->shouldSoftUpdate(options))
203             registration->softUpdate();
204         return;
205     }
206
207     if (worker->state() == ServiceWorkerState::Activating) {
208         worker->whenActivated(WTFMove(runServerWorkerAndStartFetch));
209         return;
210     }
211     ASSERT(worker->state() == ServiceWorkerState::Activated);
212     runServerWorkerAndStartFetch(true);
213 }
214
215 void WebSWServerConnection::postMessageToServiceWorker(ServiceWorkerIdentifier destinationIdentifier, MessageWithMessagePorts&& message, const ServiceWorkerOrClientIdentifier& sourceIdentifier)
216 {
217     auto* destinationWorker = server().workerByID(destinationIdentifier);
218     if (!destinationWorker)
219         return;
220
221     Optional<ServiceWorkerOrClientData> sourceData;
222     WTF::switchOn(sourceIdentifier, [&](ServiceWorkerIdentifier identifier) {
223         if (auto* sourceWorker = server().workerByID(identifier))
224             sourceData = ServiceWorkerOrClientData { sourceWorker->data() };
225     }, [&](ServiceWorkerClientIdentifier identifier) {
226         if (auto clientData = destinationWorker->findClientByIdentifier(identifier))
227             sourceData = ServiceWorkerOrClientData { *clientData };
228     });
229
230     if (!sourceData)
231         return;
232
233     if (!destinationWorker->contextConnection())
234         server().createContextConnection(destinationWorker->registrableDomain());
235
236     // It's possible this specific worker cannot be re-run (e.g. its registration has been removed)
237     server().runServiceWorkerIfNecessary(destinationIdentifier, [destinationIdentifier, message = WTFMove(message), sourceData = WTFMove(*sourceData)](auto* contextConnection) mutable {
238         if (contextConnection)
239             sendToContextProcess(*contextConnection, Messages::WebSWContextManagerConnection::PostMessageToServiceWorker { destinationIdentifier, WTFMove(message), WTFMove(sourceData) });
240     });
241 }
242
243 void WebSWServerConnection::scheduleJobInServer(ServiceWorkerJobData&& jobData)
244 {
245     RegistrableDomain registrableDomain(jobData.scopeURL);
246     if (!server().contextConnectionForRegistrableDomain(registrableDomain))
247         server().createContextConnection(registrableDomain);
248
249     SWSERVERCONNECTION_RELEASE_LOG_IF_ALLOWED("Scheduling ServiceWorker job %s in server", jobData.identifier().loggingString().utf8().data());
250     ASSERT(identifier() == jobData.connectionIdentifier());
251
252     server().scheduleJob(WTFMove(jobData));
253 }
254
255 void WebSWServerConnection::postMessageToServiceWorkerClient(DocumentIdentifier destinationContextIdentifier, const MessageWithMessagePorts& message, ServiceWorkerIdentifier sourceIdentifier, const String& sourceOrigin)
256 {
257     auto* sourceServiceWorker = server().workerByID(sourceIdentifier);
258     if (!sourceServiceWorker)
259         return;
260
261     send(Messages::WebSWClientConnection::PostMessageToServiceWorkerClient { destinationContextIdentifier, message, sourceServiceWorker->data(), sourceOrigin });
262 }
263
264 void WebSWServerConnection::matchRegistration(uint64_t registrationMatchRequestIdentifier, const SecurityOriginData& topOrigin, const URL& clientURL)
265 {
266     if (auto* registration = doRegistrationMatching(topOrigin, clientURL)) {
267         send(Messages::WebSWClientConnection::DidMatchRegistration { registrationMatchRequestIdentifier, registration->data() });
268         return;
269     }
270     send(Messages::WebSWClientConnection::DidMatchRegistration { registrationMatchRequestIdentifier, WTF::nullopt });
271 }
272
273 void WebSWServerConnection::registrationReady(uint64_t registrationReadyRequestIdentifier, ServiceWorkerRegistrationData&& registrationData)
274 {
275     send(Messages::WebSWClientConnection::RegistrationReady { registrationReadyRequestIdentifier, WTFMove(registrationData) });
276 }
277
278 void WebSWServerConnection::getRegistrations(uint64_t registrationMatchRequestIdentifier, const SecurityOriginData& topOrigin, const URL& clientURL)
279 {
280     auto registrations = server().getRegistrations(topOrigin, clientURL);
281     send(Messages::WebSWClientConnection::DidGetRegistrations { registrationMatchRequestIdentifier, registrations });
282 }
283
284 void WebSWServerConnection::registerServiceWorkerClient(SecurityOriginData&& topOrigin, ServiceWorkerClientData&& data, const Optional<ServiceWorkerRegistrationIdentifier>& controllingServiceWorkerRegistrationIdentifier, String&& userAgent)
285 {
286     auto clientOrigin = ClientOrigin { WTFMove(topOrigin), SecurityOriginData::fromURL(data.url) };
287     m_clientOrigins.add(data.identifier, clientOrigin);
288     server().registerServiceWorkerClient(WTFMove(clientOrigin), WTFMove(data), controllingServiceWorkerRegistrationIdentifier, WTFMove(userAgent));
289
290     if (!m_isThrottleable)
291         updateThrottleState();
292 }
293
294 void WebSWServerConnection::unregisterServiceWorkerClient(const ServiceWorkerClientIdentifier& clientIdentifier)
295 {
296     auto iterator = m_clientOrigins.find(clientIdentifier);
297     if (iterator == m_clientOrigins.end())
298         return;
299
300     server().unregisterServiceWorkerClient(iterator->value, clientIdentifier);
301     m_clientOrigins.remove(iterator);
302
303     if (!m_isThrottleable)
304         updateThrottleState();
305 }
306
307 bool WebSWServerConnection::hasMatchingClient(const RegistrableDomain& domain) const
308 {
309     return WTF::anyOf(m_clientOrigins.values(), [&domain](auto& origin) {
310         return domain.matches(origin.clientOrigin);
311     });
312 }
313
314 bool WebSWServerConnection::computeThrottleState(const RegistrableDomain& domain) const
315 {
316     return WTF::allOf(server().connections().values(), [&domain](auto& serverConnection) {
317         auto& connection = static_cast<WebSWServerConnection&>(*serverConnection);
318         return connection.isThrottleable() || !connection.hasMatchingClient(domain);
319     });
320 }
321
322 void WebSWServerConnection::setThrottleState(bool isThrottleable)
323 {
324     m_isThrottleable = isThrottleable;
325     updateThrottleState();
326 }
327
328 void WebSWServerConnection::updateThrottleState()
329 {
330     HashSet<SecurityOriginData> origins;
331     for (auto& origin : m_clientOrigins.values())
332         origins.add(origin.clientOrigin);
333
334     for (auto& origin : origins) {
335         if (auto* contextConnection = server().contextConnectionForRegistrableDomain(RegistrableDomain { origin })) {
336             auto& connection = static_cast<WebSWServerToContextConnection&>(*contextConnection);
337
338             if (connection.isThrottleable() == m_isThrottleable)
339                 continue;
340             bool newThrottleState = computeThrottleState(connection.registrableDomain());
341             if (connection.isThrottleable() == newThrottleState)
342                 continue;
343             connection.setThrottleState(newThrottleState);
344         }
345     }
346 }
347
348 void WebSWServerConnection::contextConnectionCreated(WebCore::SWServerToContextConnection& contextConnection)
349 {
350     auto& connection =  static_cast<WebSWServerToContextConnection&>(contextConnection);
351     connection.setThrottleState(computeThrottleState(connection.registrableDomain()));
352 }
353
354 void WebSWServerConnection::syncTerminateWorkerFromClient(WebCore::ServiceWorkerIdentifier&& identifier, CompletionHandler<void()>&& completionHandler)
355 {
356     syncTerminateWorker(WTFMove(identifier));
357     completionHandler();
358 }
359
360 PAL::SessionID WebSWServerConnection::sessionID() const
361 {
362     return server().sessionID();
363 }
364     
365 template<typename U> void WebSWServerConnection::sendToContextProcess(WebCore::SWServerToContextConnection& connection, U&& message)
366 {
367     static_cast<WebSWServerToContextConnection&>(connection).send(WTFMove(message));
368 }
369
370 } // namespace WebKit
371
372 #endif // ENABLE(SERVICE_WORKER)