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