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