Close service worker database on network process suspension
[WebKit-https.git] / Source / WebCore / workers / service / server / SWServer.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 "SWServer.h"
28
29 #if ENABLE(SERVICE_WORKER)
30
31 #include "ExceptionCode.h"
32 #include "ExceptionData.h"
33 #include "Logging.h"
34 #include "RegistrationStore.h"
35 #include "SWOriginStore.h"
36 #include "SWServerJobQueue.h"
37 #include "SWServerRegistration.h"
38 #include "SWServerToContextConnection.h"
39 #include "SWServerWorker.h"
40 #include "SecurityOrigin.h"
41 #include "ServiceWorkerClientType.h"
42 #include "ServiceWorkerContextData.h"
43 #include "ServiceWorkerFetchResult.h"
44 #include "ServiceWorkerJobData.h"
45 #include <wtf/CompletionHandler.h>
46 #include <wtf/NeverDestroyed.h>
47 #include <wtf/text/WTFString.h>
48
49 namespace WebCore {
50
51 static Seconds terminationDelay { 10_s };
52
53 SWServer::Connection::Connection(SWServer& server)
54     : m_server(server)
55     , m_identifier(SWServerConnectionIdentifier::generate())
56 {
57 }
58
59 HashSet<SWServer*>& SWServer::allServers()
60 {
61     static NeverDestroyed<HashSet<SWServer*>> servers;
62     return servers;
63 }
64
65 SWServer::~SWServer()
66 {
67     // Destroy the remaining connections before the SWServer gets destroyed since they have a raw pointer
68     // to the server and since they try to unregister clients from the server in their destructor.
69     auto connections = WTFMove(m_connections);
70     connections.clear();
71
72     allServers().remove(this);
73 }
74
75 SWServerWorker* SWServer::workerByID(ServiceWorkerIdentifier identifier) const
76 {
77     auto* worker = SWServerWorker::existingWorkerForIdentifier(identifier);
78     ASSERT(!worker || &worker->server() == this);
79     return worker;
80 }
81
82 Optional<ServiceWorkerClientData> SWServer::serviceWorkerClientWithOriginByID(const ClientOrigin& clientOrigin, const ServiceWorkerClientIdentifier& clientIdentifier) const
83 {
84     auto iterator = m_clientIdentifiersPerOrigin.find(clientOrigin);
85     if (iterator == m_clientIdentifiersPerOrigin.end())
86         return WTF::nullopt;
87
88     if (!iterator->value.identifiers.contains(clientIdentifier))
89         return WTF::nullopt;
90
91     auto clientIterator = m_clientsById.find(clientIdentifier);
92     ASSERT(clientIterator != m_clientsById.end());
93     return clientIterator->value;
94 }
95
96 String SWServer::serviceWorkerClientUserAgent(const ClientOrigin& clientOrigin) const
97 {
98     auto iterator = m_clientIdentifiersPerOrigin.find(clientOrigin);
99     if (iterator == m_clientIdentifiersPerOrigin.end())
100         return String();
101     return iterator->value.userAgent;
102 }
103
104 SWServerWorker* SWServer::activeWorkerFromRegistrationID(ServiceWorkerRegistrationIdentifier identifier)
105 {
106     auto* registration = m_registrationsByID.get(identifier);
107     return registration ? registration->activeWorker() : nullptr;
108 }
109
110 SWServerRegistration* SWServer::getRegistration(const ServiceWorkerRegistrationKey& registrationKey)
111 {
112     return m_registrations.get(registrationKey);
113 }
114
115 void SWServer::registrationStoreImportComplete()
116 {
117     ASSERT(!m_importCompleted);
118     m_importCompleted = true;
119     m_originStore->importComplete();
120
121     auto clearCallbacks = WTFMove(m_clearCompletionCallbacks);
122     for (auto& callback : clearCallbacks)
123         callback();
124
125     performGetOriginsWithRegistrationsCallbacks();
126 }
127
128 void SWServer::registrationStoreDatabaseFailedToOpen()
129 {
130     if (!m_importCompleted)
131         registrationStoreImportComplete();
132 }
133
134 void SWServer::addRegistrationFromStore(ServiceWorkerContextData&& data)
135 {
136     // Pages should not have been able to make a new registration to this key while the import was still taking place.
137     ASSERT(!m_registrations.contains(data.registration.key));
138
139     auto registration = std::make_unique<SWServerRegistration>(*this, data.registration.key, data.registration.updateViaCache, data.registration.scopeURL, data.scriptURL);
140     registration->setLastUpdateTime(data.registration.lastUpdateTime);
141     auto registrationPtr = registration.get();
142     addRegistration(WTFMove(registration));
143
144     auto worker = SWServerWorker::create(*this, *registrationPtr, data.scriptURL, data.script, data.contentSecurityPolicy, WTFMove(data.referrerPolicy), data.workerType, data.serviceWorkerIdentifier, HashMap<URL, ServiceWorkerContextData::ImportedScript> { data.scriptResourceMap });
145     registrationPtr->updateRegistrationState(ServiceWorkerRegistrationState::Active, worker.ptr());
146     worker->setState(ServiceWorkerState::Activated);
147 }
148
149 void SWServer::addRegistration(std::unique_ptr<SWServerRegistration>&& registration)
150 {
151     auto key = registration->key();
152     auto* registrationPtr = registration.get();
153     auto addResult1 = m_registrations.add(key, WTFMove(registration));
154     ASSERT_UNUSED(addResult1, addResult1.isNewEntry);
155
156     auto addResult2 = m_registrationsByID.add(registrationPtr->identifier(), registrationPtr);
157     ASSERT_UNUSED(addResult2, addResult2.isNewEntry);
158
159     m_originStore->add(key.topOrigin());
160 }
161
162 void SWServer::removeRegistration(const ServiceWorkerRegistrationKey& key)
163 {
164     auto topOrigin = key.topOrigin();
165     auto registration = m_registrations.take(key);
166     ASSERT(registration);
167     bool wasRemoved = m_registrationsByID.remove(registration->identifier());
168     ASSERT_UNUSED(wasRemoved, wasRemoved);
169
170     m_originStore->remove(topOrigin);
171     if (m_registrationStore)
172         m_registrationStore->removeRegistration(*registration);
173 }
174
175 Vector<ServiceWorkerRegistrationData> SWServer::getRegistrations(const SecurityOriginData& topOrigin, const URL& clientURL)
176 {
177     Vector<SWServerRegistration*> matchingRegistrations;
178     for (auto& item : m_registrations) {
179         if (!item.value->isUninstalling() && item.key.originIsMatching(topOrigin, clientURL))
180             matchingRegistrations.append(item.value.get());
181     }
182     // The specification mandates that registrations are returned in the insertion order.
183     std::sort(matchingRegistrations.begin(), matchingRegistrations.end(), [](auto& a, auto& b) {
184         return a->creationTime() < b->creationTime();
185     });
186     Vector<ServiceWorkerRegistrationData> matchingRegistrationDatas;
187     matchingRegistrationDatas.reserveInitialCapacity(matchingRegistrations.size());
188     for (auto* registration : matchingRegistrations)
189         matchingRegistrationDatas.uncheckedAppend(registration->data());
190     return matchingRegistrationDatas;
191 }
192
193 void SWServer::clearAll(CompletionHandler<void()>&& completionHandler)
194 {
195     if (!m_importCompleted) {
196         m_clearCompletionCallbacks.append([this, completionHandler = WTFMove(completionHandler)] () mutable {
197             ASSERT(m_importCompleted);
198             clearAll(WTFMove(completionHandler));
199         });
200         return;
201     }
202
203     m_jobQueues.clear();
204     while (!m_registrations.isEmpty())
205         m_registrations.begin()->value->clear();
206     ASSERT(m_registrationsByID.isEmpty());
207     m_pendingContextDatas.clear();
208     m_originStore->clearAll();
209     if (m_registrationStore)
210         m_registrationStore->clearAll(WTFMove(completionHandler));
211 }
212
213 void SWServer::startSuspension(CompletionHandler<void()>&& completionHandler)
214 {
215     if (m_registrationStore)
216         m_registrationStore->startSuspension(WTFMove(completionHandler));
217 }
218
219 void SWServer::endSuspension()
220 {
221     if (m_registrationStore)
222         m_registrationStore->endSuspension();
223 }
224
225 void SWServer::clear(const SecurityOriginData& securityOrigin, CompletionHandler<void()>&& completionHandler)
226 {
227     if (!m_importCompleted) {
228         m_clearCompletionCallbacks.append([this, securityOrigin, completionHandler = WTFMove(completionHandler)] () mutable {
229             ASSERT(m_importCompleted);
230             clear(securityOrigin, WTFMove(completionHandler));
231         });
232         return;
233     }
234
235     m_jobQueues.removeIf([&](auto& keyAndValue) {
236         return keyAndValue.key.relatesToOrigin(securityOrigin);
237     });
238
239     Vector<SWServerRegistration*> registrationsToRemove;
240     for (auto& keyAndValue : m_registrations) {
241         if (keyAndValue.key.relatesToOrigin(securityOrigin))
242             registrationsToRemove.append(keyAndValue.value.get());
243     }
244
245     for (auto& contextDatas : m_pendingContextDatas.values()) {
246         contextDatas.removeAllMatching([&](auto& contextData) {
247             return contextData.registration.key.relatesToOrigin(securityOrigin);
248         });
249     }
250
251     if (registrationsToRemove.isEmpty()) {
252         completionHandler();
253         return;
254     }
255
256     // Calling SWServerRegistration::clear() takes care of updating m_registrations, m_originStore and m_registrationStore.
257     for (auto* registration : registrationsToRemove)
258         registration->clear();
259
260     if (m_registrationStore)
261         m_registrationStore->flushChanges(WTFMove(completionHandler));
262 }
263
264 void SWServer::Connection::finishFetchingScriptInServer(const ServiceWorkerFetchResult& result)
265 {
266     m_server.scriptFetchFinished(*this, result);
267 }
268
269 void SWServer::Connection::didResolveRegistrationPromise(const ServiceWorkerRegistrationKey& key)
270 {
271     m_server.didResolveRegistrationPromise(*this, key);
272 }
273
274 void SWServer::Connection::addServiceWorkerRegistrationInServer(ServiceWorkerRegistrationIdentifier identifier)
275 {
276     m_server.addClientServiceWorkerRegistration(*this, identifier);
277 }
278
279 void SWServer::Connection::removeServiceWorkerRegistrationInServer(ServiceWorkerRegistrationIdentifier identifier)
280 {
281     m_server.removeClientServiceWorkerRegistration(*this, identifier);
282 }
283
284 void SWServer::Connection::syncTerminateWorker(ServiceWorkerIdentifier identifier)
285 {
286     if (auto* worker = m_server.workerByID(identifier))
287         m_server.syncTerminateWorker(*worker);
288 }
289
290 SWServer::SWServer(UniqueRef<SWOriginStore>&& originStore, String&& registrationDatabaseDirectory, PAL::SessionID sessionID)
291     : m_originStore(WTFMove(originStore))
292     , m_sessionID(sessionID)
293 {
294     ASSERT(!registrationDatabaseDirectory.isEmpty() || m_sessionID.isEphemeral());
295     if (!m_sessionID.isEphemeral())
296         m_registrationStore = std::make_unique<RegistrationStore>(*this, WTFMove(registrationDatabaseDirectory));
297     else
298         registrationStoreImportComplete();
299
300     UNUSED_PARAM(registrationDatabaseDirectory);
301     allServers().add(this);
302 }
303
304 // https://w3c.github.io/ServiceWorker/#schedule-job-algorithm
305 void SWServer::scheduleJob(ServiceWorkerJobData&& jobData)
306 {
307     ASSERT(m_connections.contains(jobData.connectionIdentifier()));
308
309     // FIXME: Per the spec, check if this job is equivalent to the last job on the queue.
310     // If it is, stack it along with that job.
311
312     auto& jobQueue = *m_jobQueues.ensure(jobData.registrationKey(), [this, &jobData] {
313         return std::make_unique<SWServerJobQueue>(*this, jobData.registrationKey());
314     }).iterator->value;
315
316     jobQueue.enqueueJob(jobData);
317     if (jobQueue.size() == 1)
318         jobQueue.runNextJob();
319 }
320
321 void SWServer::rejectJob(const ServiceWorkerJobData& jobData, const ExceptionData& exceptionData)
322 {
323     LOG(ServiceWorker, "Rejected ServiceWorker job %s in server", jobData.identifier().loggingString().utf8().data());
324     auto* connection = m_connections.get(jobData.connectionIdentifier());
325     if (!connection)
326         return;
327
328     connection->rejectJobInClient(jobData.identifier().jobIdentifier, exceptionData);
329 }
330
331 void SWServer::resolveRegistrationJob(const ServiceWorkerJobData& jobData, const ServiceWorkerRegistrationData& registrationData, ShouldNotifyWhenResolved shouldNotifyWhenResolved)
332 {
333     LOG(ServiceWorker, "Resolved ServiceWorker job %s in server with registration %s", jobData.identifier().loggingString().utf8().data(), registrationData.identifier.loggingString().utf8().data());
334     auto* connection = m_connections.get(jobData.connectionIdentifier());
335     if (!connection)
336         return;
337
338     connection->resolveRegistrationJobInClient(jobData.identifier().jobIdentifier, registrationData, shouldNotifyWhenResolved);
339 }
340
341 void SWServer::resolveUnregistrationJob(const ServiceWorkerJobData& jobData, const ServiceWorkerRegistrationKey& registrationKey, bool unregistrationResult)
342 {
343     auto* connection = m_connections.get(jobData.connectionIdentifier());
344     if (!connection)
345         return;
346
347     connection->resolveUnregistrationJobInClient(jobData.identifier().jobIdentifier, registrationKey, unregistrationResult);
348 }
349
350 void SWServer::startScriptFetch(const ServiceWorkerJobData& jobData, FetchOptions::Cache cachePolicy)
351 {
352     LOG(ServiceWorker, "Server issuing startScriptFetch for current job %s in client", jobData.identifier().loggingString().utf8().data());
353     auto* connection = m_connections.get(jobData.connectionIdentifier());
354     ASSERT_WITH_MESSAGE(connection, "If the connection was lost, this job should have been cancelled");
355     if (connection)
356         connection->startScriptFetchInClient(jobData.identifier().jobIdentifier, jobData.registrationKey(), cachePolicy);
357 }
358
359 void SWServer::scriptFetchFinished(Connection& connection, const ServiceWorkerFetchResult& result)
360 {
361     LOG(ServiceWorker, "Server handling scriptFetchFinished for current job %s in client", result.jobDataIdentifier.loggingString().utf8().data());
362
363     ASSERT(m_connections.contains(result.jobDataIdentifier.connectionIdentifier));
364
365     auto jobQueue = m_jobQueues.get(result.registrationKey);
366     if (!jobQueue)
367         return;
368
369     jobQueue->scriptFetchFinished(connection, result);
370 }
371
372 void SWServer::scriptContextFailedToStart(const Optional<ServiceWorkerJobDataIdentifier>& jobDataIdentifier, SWServerWorker& worker, const String& message)
373 {
374     if (!jobDataIdentifier)
375         return;
376
377     RELEASE_LOG_ERROR(ServiceWorker, "%p - SWServer::scriptContextFailedToStart: Failed to start SW for job %s, error: %s", this, jobDataIdentifier->loggingString().utf8().data(), message.utf8().data());
378
379     auto* jobQueue = m_jobQueues.get(worker.registrationKey());
380     if (!jobQueue || !jobQueue->isCurrentlyProcessingJob(*jobDataIdentifier)) {
381         // The job which started this worker has been canceled, terminate this worker.
382         terminatePreinstallationWorker(worker);
383         return;
384     }
385     jobQueue->scriptContextFailedToStart(*jobDataIdentifier, worker.identifier(), message);
386 }
387
388 void SWServer::scriptContextStarted(const Optional<ServiceWorkerJobDataIdentifier>& jobDataIdentifier, SWServerWorker& worker)
389 {
390     if (!jobDataIdentifier)
391         return;
392
393     auto* jobQueue = m_jobQueues.get(worker.registrationKey());
394     if (!jobQueue || !jobQueue->isCurrentlyProcessingJob(*jobDataIdentifier)) {
395         // The job which started this worker has been canceled, terminate this worker.
396         terminatePreinstallationWorker(worker);
397         return;
398     }
399     jobQueue->scriptContextStarted(*jobDataIdentifier, worker.identifier());
400 }
401
402 void SWServer::terminatePreinstallationWorker(SWServerWorker& worker)
403 {
404     worker.terminate();
405     auto* registration = getRegistration(worker.registrationKey());
406     if (registration && registration->preInstallationWorker() == &worker)
407         registration->setPreInstallationWorker(nullptr);
408 }
409
410 void SWServer::didFinishInstall(const Optional<ServiceWorkerJobDataIdentifier>& jobDataIdentifier, SWServerWorker& worker, bool wasSuccessful)
411 {
412     if (!jobDataIdentifier)
413         return;
414
415     if (wasSuccessful)
416         RELEASE_LOG(ServiceWorker, "%p - SWServer::didFinishInstall: Successfuly finished SW install for job %s", this, jobDataIdentifier->loggingString().utf8().data());
417     else
418         RELEASE_LOG_ERROR(ServiceWorker, "%p - SWServer::didFinishInstall: Failed SW install for job %s", this, jobDataIdentifier->loggingString().utf8().data());
419
420     if (auto* jobQueue = m_jobQueues.get(worker.registrationKey()))
421         jobQueue->didFinishInstall(*jobDataIdentifier, worker.identifier(), wasSuccessful);
422 }
423
424 void SWServer::didFinishActivation(SWServerWorker& worker)
425 {
426     RELEASE_LOG(ServiceWorker, "%p - SWServer::didFinishActivation: Finished activation for service worker %llu", this, worker.identifier().toUInt64());
427
428     auto* registration = getRegistration(worker.registrationKey());
429     if (!registration)
430         return;
431
432     if (m_registrationStore)
433         m_registrationStore->updateRegistration(worker.contextData());
434     registration->didFinishActivation(worker.identifier());
435 }
436
437 // https://w3c.github.io/ServiceWorker/#clients-getall
438 void SWServer::matchAll(SWServerWorker& worker, const ServiceWorkerClientQueryOptions& options, ServiceWorkerClientsMatchAllCallback&& callback)
439 {
440     // FIXME: Support reserved client filtering.
441     // FIXME: Support WindowClient additional properties.
442
443     Vector<ServiceWorkerClientData> matchingClients;
444     forEachClientForOrigin(worker.origin(), [&](auto& clientData) {
445         if (!options.includeUncontrolled) {
446             auto registrationIdentifier = m_clientToControllingRegistration.get(clientData.identifier);
447             if (worker.data().registrationIdentifier != registrationIdentifier)
448                 return;
449             if (&worker != this->activeWorkerFromRegistrationID(registrationIdentifier))
450                 return;
451         }
452         if (options.type != ServiceWorkerClientType::All && options.type != clientData.type)
453             return;
454         matchingClients.append(clientData);
455     });
456     callback(WTFMove(matchingClients));
457 }
458
459 void SWServer::forEachClientForOrigin(const ClientOrigin& origin, const WTF::Function<void(ServiceWorkerClientData&)>& apply)
460 {
461     auto iterator = m_clientIdentifiersPerOrigin.find(origin);
462     if (iterator == m_clientIdentifiersPerOrigin.end())
463         return;
464
465     for (auto& clientIdentifier : iterator->value.identifiers) {
466         auto clientIterator = m_clientsById.find(clientIdentifier);
467         ASSERT(clientIterator != m_clientsById.end());
468         apply(clientIterator->value);
469     }
470 }
471
472 void SWServer::claim(SWServerWorker& worker)
473 {
474     auto& origin = worker.origin();
475     forEachClientForOrigin(origin, [&](auto& clientData) {
476         auto* registration = this->doRegistrationMatching(origin.topOrigin, clientData.url);
477         if (!(registration && registration->key() == worker.registrationKey()))
478             return;
479
480         auto result = m_clientToControllingRegistration.add(clientData.identifier, registration->identifier());
481         if (!result.isNewEntry) {
482             auto previousIdentifier = result.iterator->value;
483             if (previousIdentifier == registration->identifier())
484                 return;
485             result.iterator->value = registration->identifier();
486             if (auto* controllingRegistration = m_registrationsByID.get(previousIdentifier))
487                 controllingRegistration->removeClientUsingRegistration(clientData.identifier);
488         }
489         registration->controlClient(clientData.identifier);
490     });
491 }
492
493 void SWServer::didResolveRegistrationPromise(Connection& connection, const ServiceWorkerRegistrationKey& registrationKey)
494 {
495     ASSERT_UNUSED(connection, m_connections.contains(connection.identifier()));
496
497     if (auto* jobQueue = m_jobQueues.get(registrationKey))
498         jobQueue->didResolveRegistrationPromise();
499 }
500
501 void SWServer::addClientServiceWorkerRegistration(Connection& connection, ServiceWorkerRegistrationIdentifier identifier)
502 {
503     auto* registration = m_registrationsByID.get(identifier);
504     if (!registration) {
505         LOG_ERROR("Request to add client-side ServiceWorkerRegistration to non-existent server-side registration");
506         return;
507     }
508     
509     registration->addClientServiceWorkerRegistration(connection.identifier());
510 }
511
512 void SWServer::removeClientServiceWorkerRegistration(Connection& connection, ServiceWorkerRegistrationIdentifier identifier)
513 {
514     if (auto* registration = m_registrationsByID.get(identifier))
515         registration->removeClientServiceWorkerRegistration(connection.identifier());
516 }
517
518 void SWServer::updateWorker(Connection&, const ServiceWorkerJobDataIdentifier& jobDataIdentifier, SWServerRegistration& registration, const URL& url, const String& script, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicy, const String& referrerPolicy, WorkerType type, HashMap<URL, ServiceWorkerContextData::ImportedScript>&& scriptResourceMap)
519 {
520     tryInstallContextData({ jobDataIdentifier, registration.data(), ServiceWorkerIdentifier::generate(), script, contentSecurityPolicy, referrerPolicy, url, type, sessionID(), false, WTFMove(scriptResourceMap) });
521 }
522
523 void SWServer::tryInstallContextData(ServiceWorkerContextData&& data)
524 {
525     RegistrableDomain registrableDomain(data.scriptURL);
526     auto* connection = SWServerToContextConnection::connectionForRegistrableDomain(registrableDomain);
527     if (!connection) {
528         m_pendingContextDatas.ensure(WTFMove(registrableDomain), [] {
529             return Vector<ServiceWorkerContextData> { };
530         }).iterator->value.append(WTFMove(data));
531         return;
532     }
533     
534     installContextData(data);
535 }
536
537 void SWServer::serverToContextConnectionCreated(SWServerToContextConnection& contextConnection)
538 {
539     auto pendingContextDatas = m_pendingContextDatas.take(contextConnection.registrableDomain());
540     for (auto& data : pendingContextDatas)
541         installContextData(data);
542
543     auto serviceWorkerRunRequests = m_serviceWorkerRunRequests.take(contextConnection.registrableDomain());
544     for (auto& item : serviceWorkerRunRequests) {
545         bool success = runServiceWorker(item.key);
546         for (auto& callback : item.value)
547             callback(success ? &contextConnection : nullptr);
548     }
549 }
550
551 void SWServer::installContextData(const ServiceWorkerContextData& data)
552 {
553     ASSERT_WITH_MESSAGE(!data.loadedFromDisk, "Workers we just read from disk should only be launched as needed");
554
555     if (data.jobDataIdentifier) {
556         // Abort if the job that scheduled this has been cancelled.
557         auto* jobQueue = m_jobQueues.get(data.registration.key);
558         if (!jobQueue || !jobQueue->isCurrentlyProcessingJob(*data.jobDataIdentifier))
559             return;
560     }
561
562     auto* registration = m_registrations.get(data.registration.key);
563     RELEASE_ASSERT(registration);
564
565     auto worker = SWServerWorker::create(*this, *registration, data.scriptURL, data.script, data.contentSecurityPolicy, String { data.referrerPolicy }, data.workerType, data.serviceWorkerIdentifier, HashMap<URL, ServiceWorkerContextData::ImportedScript> { data.scriptResourceMap });
566
567     auto* connection = worker->contextConnection();
568     ASSERT(connection);
569
570     registration->setPreInstallationWorker(worker.ptr());
571     worker->setState(SWServerWorker::State::Running);
572     auto userAgent = worker->userAgent();
573     auto result = m_runningOrTerminatingWorkers.add(data.serviceWorkerIdentifier, WTFMove(worker));
574     ASSERT_UNUSED(result, result.isNewEntry);
575
576     connection->installServiceWorkerContext(data, m_sessionID, userAgent);
577 }
578
579 void SWServer::runServiceWorkerIfNecessary(ServiceWorkerIdentifier identifier, RunServiceWorkerCallback&& callback)
580 {
581     auto* worker = workerByID(identifier);
582     if (!worker) {
583         callback(nullptr);
584         return;
585     }
586
587     auto* contextConnection = worker->contextConnection();
588     if (worker->isRunning()) {
589         ASSERT(contextConnection);
590         callback(contextConnection);
591         return;
592     }
593
594     if (!contextConnection) {
595         auto& serviceWorkerRunRequestsForOrigin = m_serviceWorkerRunRequests.ensure(worker->registrableDomain(), [] {
596             return HashMap<ServiceWorkerIdentifier, Vector<RunServiceWorkerCallback>> { };
597         }).iterator->value;
598         serviceWorkerRunRequestsForOrigin.ensure(identifier, [&] {
599             return Vector<RunServiceWorkerCallback> { };
600         }).iterator->value.append(WTFMove(callback));
601         return;
602     }
603
604     bool success = runServiceWorker(identifier);
605     callback(success ? contextConnection : nullptr);
606 }
607
608 bool SWServer::runServiceWorker(ServiceWorkerIdentifier identifier)
609 {
610     auto* worker = workerByID(identifier);
611     if (!worker)
612         return false;
613
614     // If the registration for a working has been removed then the request to run
615     // the worker is moot.
616     if (!getRegistration(worker->registrationKey()))
617         return false;
618
619     auto addResult = m_runningOrTerminatingWorkers.add(identifier, *worker);
620     ASSERT_UNUSED(addResult, addResult.isNewEntry || worker->isTerminating());
621
622     worker->setState(SWServerWorker::State::Running);
623
624     auto* contextConnection = worker->contextConnection();
625     ASSERT(contextConnection);
626
627     contextConnection->installServiceWorkerContext(worker->contextData(), m_sessionID, worker->userAgent());
628
629     return true;
630 }
631
632 void SWServer::terminateWorker(SWServerWorker& worker)
633 {
634     terminateWorkerInternal(worker, Asynchronous);
635 }
636
637 void SWServer::syncTerminateWorker(SWServerWorker& worker)
638 {
639     terminateWorkerInternal(worker, Synchronous);
640 }
641
642 void SWServer::terminateWorkerInternal(SWServerWorker& worker, TerminationMode mode)
643 {
644     ASSERT(m_runningOrTerminatingWorkers.get(worker.identifier()) == &worker);
645     ASSERT(worker.isRunning());
646
647     RELEASE_LOG(ServiceWorker, "%p - SWServer::terminateWorkerInternal: Terminating service worker %llu", this, worker.identifier().toUInt64());
648
649     worker.setState(SWServerWorker::State::Terminating);
650
651     auto* contextConnection = worker.contextConnection();
652     ASSERT(contextConnection);
653     if (!contextConnection) {
654         LOG_ERROR("Request to terminate a worker whose context connection does not exist");
655         workerContextTerminated(worker);
656         return;
657     }
658
659     switch (mode) {
660     case Asynchronous:
661         contextConnection->terminateWorker(worker.identifier());
662         break;
663     case Synchronous:
664         contextConnection->syncTerminateWorker(worker.identifier());
665         break;
666     };
667 }
668
669 void SWServer::markAllWorkersForRegistrableDomainAsTerminated(const RegistrableDomain& registrableDomain)
670 {
671     Vector<SWServerWorker*> terminatedWorkers;
672     for (auto& worker : m_runningOrTerminatingWorkers.values()) {
673         if (worker->registrableDomain() == registrableDomain)
674             terminatedWorkers.append(worker.ptr());
675     }
676     for (auto& terminatedWorker : terminatedWorkers)
677         workerContextTerminated(*terminatedWorker);
678 }
679
680 void SWServer::workerContextTerminated(SWServerWorker& worker)
681 {
682     worker.setState(SWServerWorker::State::NotRunning);
683
684     if (auto* jobQueue = m_jobQueues.get(worker.registrationKey()))
685         jobQueue->cancelJobsFromServiceWorker(worker.identifier());
686
687     // At this point if no registrations are referencing the worker then it will be destroyed,
688     // removing itself from the m_workersByID map.
689     auto result = m_runningOrTerminatingWorkers.take(worker.identifier());
690     ASSERT_UNUSED(result, result && result->ptr() == &worker);
691 }
692
693 void SWServer::fireInstallEvent(SWServerWorker& worker)
694 {
695     auto* contextConnection = worker.contextConnection();
696     if (!contextConnection) {
697         LOG_ERROR("Request to fire install event on a worker whose context connection does not exist");
698         return;
699     }
700
701     contextConnection->fireInstallEvent(worker.identifier());
702 }
703
704 void SWServer::fireActivateEvent(SWServerWorker& worker)
705 {
706     auto* contextConnection = worker.contextConnection();
707     if (!contextConnection) {
708         LOG_ERROR("Request to fire install event on a worker whose context connection does not exist");
709         return;
710     }
711
712     contextConnection->fireActivateEvent(worker.identifier());
713 }
714
715 void SWServer::addConnection(std::unique_ptr<Connection>&& connection)
716 {
717     auto identifier = connection->identifier();
718     ASSERT(!m_connections.contains(identifier));
719     m_connections.add(identifier, WTFMove(connection));
720 }
721
722 void SWServer::removeConnection(SWServerConnectionIdentifier connectionIdentifier)
723 {
724     ASSERT(m_connections.contains(connectionIdentifier));
725     m_connections.remove(connectionIdentifier);
726
727     for (auto& registration : m_registrations.values())
728         registration->unregisterServerConnection(connectionIdentifier);
729
730     for (auto& jobQueue : m_jobQueues.values())
731         jobQueue->cancelJobsFromConnection(connectionIdentifier);
732 }
733
734 SWServerRegistration* SWServer::doRegistrationMatching(const SecurityOriginData& topOrigin, const URL& clientURL)
735 {
736     SWServerRegistration* selectedRegistration = nullptr;
737     for (auto& registration : m_registrations.values()) {
738         if (!registration->key().isMatching(topOrigin, clientURL))
739             continue;
740         if (!selectedRegistration || selectedRegistration->key().scopeLength() < registration->key().scopeLength())
741             selectedRegistration = registration.get();
742     }
743
744     return (selectedRegistration && !selectedRegistration->isUninstalling()) ? selectedRegistration : nullptr;
745 }
746
747 SWServerRegistration* SWServer::registrationFromServiceWorkerIdentifier(ServiceWorkerIdentifier identifier)
748 {
749     auto iterator = m_runningOrTerminatingWorkers.find(identifier);
750     if (iterator == m_runningOrTerminatingWorkers.end())
751         return nullptr;
752
753     return m_registrations.get(iterator->value->registrationKey());
754 }
755
756 void SWServer::registerServiceWorkerClient(ClientOrigin&& clientOrigin, ServiceWorkerClientData&& data, const Optional<ServiceWorkerRegistrationIdentifier>& controllingServiceWorkerRegistrationIdentifier, String&& userAgent)
757 {
758     auto clientIdentifier = data.identifier;
759
760     ASSERT(!m_clientsById.contains(clientIdentifier));
761     m_clientsById.add(clientIdentifier, WTFMove(data));
762
763     auto& clientIdentifiersForOrigin = m_clientIdentifiersPerOrigin.ensure(clientOrigin, [] {
764         return Clients { };
765     }).iterator->value;
766
767     ASSERT(!clientIdentifiersForOrigin.identifiers.contains(clientIdentifier));
768     clientIdentifiersForOrigin.identifiers.append(clientIdentifier);
769
770     if (!clientIdentifiersForOrigin.userAgent.isNull() && clientIdentifiersForOrigin.userAgent != userAgent)
771         RELEASE_LOG_ERROR(ServiceWorker, "%p - SWServer::registerServiceWorkerClient: Service worker has clients using different user agents", this);
772     clientIdentifiersForOrigin.userAgent = WTFMove(userAgent);
773
774     clientIdentifiersForOrigin.terminateServiceWorkersTimer = nullptr;
775
776     m_clientsByRegistrableDomain.ensure(clientOrigin.clientRegistrableDomain(), [] {
777         return HashSet<ServiceWorkerClientIdentifier> { };
778     }).iterator->value.add(clientIdentifier);
779
780     if (!controllingServiceWorkerRegistrationIdentifier)
781         return;
782
783     auto* controllingRegistration = m_registrationsByID.get(*controllingServiceWorkerRegistrationIdentifier);
784     if (!controllingRegistration || !controllingRegistration->activeWorker())
785         return;
786
787     controllingRegistration->addClientUsingRegistration(clientIdentifier);
788     ASSERT(!m_clientToControllingRegistration.contains(clientIdentifier));
789     m_clientToControllingRegistration.add(clientIdentifier, *controllingServiceWorkerRegistrationIdentifier);
790 }
791
792 void SWServer::unregisterServiceWorkerClient(const ClientOrigin& clientOrigin, ServiceWorkerClientIdentifier clientIdentifier)
793 {
794     auto clientRegistrableDomain = clientOrigin.clientRegistrableDomain();
795
796     bool wasRemoved = m_clientsById.remove(clientIdentifier);
797     ASSERT_UNUSED(wasRemoved, wasRemoved);
798
799     auto iterator = m_clientIdentifiersPerOrigin.find(clientOrigin);
800     ASSERT(iterator != m_clientIdentifiersPerOrigin.end());
801
802     auto& clientIdentifiers = iterator->value.identifiers;
803     clientIdentifiers.removeFirstMatching([&] (const auto& identifier) {
804         return clientIdentifier == identifier;
805     });
806
807     if (clientIdentifiers.isEmpty()) {
808         ASSERT(!iterator->value.terminateServiceWorkersTimer);
809         iterator->value.terminateServiceWorkersTimer = std::make_unique<Timer>([clientOrigin, clientRegistrableDomain, this] {
810             Vector<SWServerWorker*> workersToTerminate;
811             for (auto& worker : m_runningOrTerminatingWorkers.values()) {
812                 if (worker->isRunning() && worker->origin() == clientOrigin)
813                     workersToTerminate.append(worker.ptr());
814             }
815             for (auto* worker : workersToTerminate)
816                 terminateWorker(*worker);
817
818             if (!m_clientsByRegistrableDomain.contains(clientRegistrableDomain)) {
819                 if (auto* connection = SWServerToContextConnection::connectionForRegistrableDomain(clientRegistrableDomain))
820                     connection->connectionMayNoLongerBeNeeded();
821             }
822
823             m_clientIdentifiersPerOrigin.remove(clientOrigin);
824         });
825         iterator->value.terminateServiceWorkersTimer->startOneShot(m_shouldDisableServiceWorkerProcessTerminationDelay ? 0_s : terminationDelay);
826     }
827
828     auto clientsByRegistrableDomainIterator = m_clientsByRegistrableDomain.find(clientRegistrableDomain);
829     ASSERT(clientsByRegistrableDomainIterator != m_clientsByRegistrableDomain.end());
830     auto& clientsForRegistrableDomain = clientsByRegistrableDomainIterator->value;
831     clientsForRegistrableDomain.remove(clientIdentifier);
832     if (clientsForRegistrableDomain.isEmpty())
833         m_clientsByRegistrableDomain.remove(clientsByRegistrableDomainIterator);
834
835     auto registrationIterator = m_clientToControllingRegistration.find(clientIdentifier);
836     if (registrationIterator == m_clientToControllingRegistration.end())
837         return;
838
839     if (auto* registration = m_registrationsByID.get(registrationIterator->value))
840         registration->removeClientUsingRegistration(clientIdentifier);
841
842     m_clientToControllingRegistration.remove(registrationIterator);
843 }
844
845 bool SWServer::needsServerToContextConnectionForRegistrableDomain(const RegistrableDomain& registrableDomain) const
846 {
847     return m_clientsByRegistrableDomain.contains(registrableDomain);
848 }
849
850 void SWServer::resolveRegistrationReadyRequests(SWServerRegistration& registration)
851 {
852     for (auto& connection : m_connections.values())
853         connection->resolveRegistrationReadyRequests(registration);
854 }
855
856 void SWServer::Connection::whenRegistrationReady(uint64_t registrationReadyRequestIdentifier, const SecurityOriginData& topOrigin, const URL& clientURL)
857 {
858     if (auto* registration = doRegistrationMatching(topOrigin, clientURL)) {
859         if (registration->activeWorker()) {
860             registrationReady(registrationReadyRequestIdentifier, registration->data());
861             return;
862         }
863     }
864     m_registrationReadyRequests.append({ topOrigin, clientURL, registrationReadyRequestIdentifier });
865 }
866
867 void SWServer::Connection::resolveRegistrationReadyRequests(SWServerRegistration& registration)
868 {
869     m_registrationReadyRequests.removeAllMatching([&](auto& request) {
870         if (!registration.key().isMatching(request.topOrigin, request.clientURL))
871             return false;
872
873         this->registrationReady(request.identifier, registration.data());
874         return true;
875     });
876 }
877
878 void SWServer::getOriginsWithRegistrations(Function<void(const HashSet<SecurityOriginData>&)>&& callback)
879 {
880     m_getOriginsWithRegistrationsCallbacks.append(WTFMove(callback));
881
882     if (m_importCompleted)
883         performGetOriginsWithRegistrationsCallbacks();
884 }
885
886 void SWServer::performGetOriginsWithRegistrationsCallbacks()
887 {
888     ASSERT(isMainThread());
889     ASSERT(m_importCompleted);
890
891     if (m_getOriginsWithRegistrationsCallbacks.isEmpty())
892         return;
893
894     HashSet<SecurityOriginData> originsWithRegistrations;
895     for (auto& key : m_registrations.keys()) {
896         originsWithRegistrations.add(key.topOrigin());
897         originsWithRegistrations.add(SecurityOriginData { key.scope().protocol().toString(), key.scope().host().toString(), key.scope().port() });
898     }
899
900     auto callbacks = WTFMove(m_getOriginsWithRegistrationsCallbacks);
901     for (auto& callback : callbacks)
902         callback(originsWithRegistrations);
903 }
904
905 } // namespace WebCore
906
907 #endif // ENABLE(SERVICE_WORKER)