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