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