Add support for ServiceWorkerContainer.prototype.ready
[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 "SWOriginStore.h"
35 #include "SWServerJobQueue.h"
36 #include "SWServerRegistration.h"
37 #include "SWServerToContextConnection.h"
38 #include "SWServerWorker.h"
39 #include "SecurityOrigin.h"
40 #include "ServiceWorkerClientType.h"
41 #include "ServiceWorkerContextData.h"
42 #include "ServiceWorkerFetchResult.h"
43 #include "ServiceWorkerJobData.h"
44 #include <wtf/CompletionHandler.h>
45 #include <wtf/NeverDestroyed.h>
46 #include <wtf/text/WTFString.h>
47
48 namespace WebCore {
49
50 static ServiceWorkerIdentifier generateServiceWorkerIdentifier()
51 {
52     return generateObjectIdentifier<ServiceWorkerIdentifierType>();
53 }
54
55 static Seconds terminationDelay { 60_s };
56
57 SWServer::Connection::Connection(SWServer& server)
58     : m_server(server)
59     , m_identifier(generateObjectIdentifier<SWServerConnectionIdentifierType>())
60 {
61     m_server.registerConnection(*this);
62 }
63
64 SWServer::Connection::~Connection()
65 {
66     m_server.unregisterConnection(*this);
67 }
68
69 HashSet<SWServer*>& SWServer::allServers()
70 {
71     static NeverDestroyed<HashSet<SWServer*>> servers;
72     return servers;
73 }
74
75 SWServer::~SWServer()
76 {
77     RELEASE_ASSERT(m_connections.isEmpty());
78     RELEASE_ASSERT(m_registrations.isEmpty());
79     RELEASE_ASSERT(m_jobQueues.isEmpty());
80
81     ASSERT(m_taskQueue.isEmpty());
82     ASSERT(m_taskReplyQueue.isEmpty());
83
84     // For a SWServer to be cleanly shut down its thread must have finished and gone away.
85     // At this stage in development of the feature that actually never happens.
86     // But once it does start happening, this ASSERT will catch us doing it wrong.
87     Locker<Lock> locker(m_taskThreadLock);
88     ASSERT(!m_taskThread);
89     
90     allServers().remove(this);
91 }
92
93 SWServerWorker* SWServer::workerByID(ServiceWorkerIdentifier identifier) const
94 {
95     auto* worker = SWServerWorker::existingWorkerForIdentifier(identifier);
96     ASSERT(!worker || &worker->server() == this);
97     return worker;
98 }
99
100 SWServerRegistration* SWServer::getRegistration(const ServiceWorkerRegistrationKey& registrationKey)
101 {
102     return m_registrations.get(registrationKey);
103 }
104
105 void SWServer::addRegistration(std::unique_ptr<SWServerRegistration>&& registration)
106 {
107     auto key = registration->key();
108     auto* registrationPtr = registration.get();
109     auto addResult1 = m_registrations.add(key, WTFMove(registration));
110     ASSERT_UNUSED(addResult1, addResult1.isNewEntry);
111
112     auto addResult2 = m_registrationsByID.add(registrationPtr->identifier(), registrationPtr);
113     ASSERT_UNUSED(addResult2, addResult2.isNewEntry);
114
115     m_originStore->add(key.topOrigin().securityOrigin());
116 }
117
118 void SWServer::removeRegistration(const ServiceWorkerRegistrationKey& key)
119 {
120     auto topOrigin = key.topOrigin().securityOrigin();
121     auto registration = m_registrations.take(key);
122     ASSERT(registration);
123     bool wasRemoved = m_registrationsByID.remove(registration->identifier());
124     ASSERT_UNUSED(wasRemoved, wasRemoved);
125
126     m_originStore->remove(topOrigin);
127 }
128
129 Vector<ServiceWorkerRegistrationData> SWServer::getRegistrations(const SecurityOriginData& topOrigin, const URL& clientURL)
130 {
131     Vector<SWServerRegistration*> matchingRegistrations;
132     for (auto& item : m_registrations) {
133         if (!item.value->isUninstalling() && item.key.originIsMatching(topOrigin, clientURL))
134             matchingRegistrations.append(item.value.get());
135     }
136     // The specification mandates that registrations are returned in the insertion order.
137     std::sort(matchingRegistrations.begin(), matchingRegistrations.end(), [](auto& a, auto& b) {
138         return a->creationTime() < b->creationTime();
139     });
140     Vector<ServiceWorkerRegistrationData> matchingRegistrationDatas;
141     matchingRegistrationDatas.reserveInitialCapacity(matchingRegistrations.size());
142     for (auto* registration : matchingRegistrations)
143         matchingRegistrationDatas.uncheckedAppend(registration->data());
144     return matchingRegistrationDatas;
145 }
146
147 void SWServer::clearAll()
148 {
149     m_jobQueues.clear();
150     while (!m_registrations.isEmpty())
151         m_registrations.begin()->value->clear();
152     ASSERT(m_registrationsByID.isEmpty());
153     m_originStore->clearAll();
154 }
155
156 void SWServer::clear(const SecurityOrigin& origin)
157 {
158     m_originStore->clear(origin);
159
160     // FIXME: We should clear entries in m_registrations, m_jobQueues and m_workersByID.
161 }
162
163 void SWServer::Connection::scheduleJobInServer(const ServiceWorkerJobData& jobData)
164 {
165     LOG(ServiceWorker, "Scheduling ServiceWorker job %s in server", jobData.identifier().loggingString().utf8().data());
166     ASSERT(identifier() == jobData.connectionIdentifier());
167
168     m_server.scheduleJob(jobData);
169 }
170
171 void SWServer::Connection::finishFetchingScriptInServer(const ServiceWorkerFetchResult& result)
172 {
173     m_server.scriptFetchFinished(*this, result);
174 }
175
176 void SWServer::Connection::didResolveRegistrationPromise(const ServiceWorkerRegistrationKey& key)
177 {
178     m_server.didResolveRegistrationPromise(*this, key);
179 }
180
181 void SWServer::Connection::addServiceWorkerRegistrationInServer(ServiceWorkerRegistrationIdentifier identifier)
182 {
183     m_server.addClientServiceWorkerRegistration(*this, identifier);
184 }
185
186 void SWServer::Connection::removeServiceWorkerRegistrationInServer(ServiceWorkerRegistrationIdentifier identifier)
187 {
188     m_server.removeClientServiceWorkerRegistration(*this, identifier);
189 }
190
191 void SWServer::Connection::syncTerminateWorker(ServiceWorkerIdentifier identifier)
192 {
193     if (auto* worker = m_server.workerByID(identifier))
194         m_server.syncTerminateWorker(*worker);
195 }
196
197 SWServer::SWServer(UniqueRef<SWOriginStore>&& originStore, const String& registrationDatabaseDirectory)
198     : m_originStore(WTFMove(originStore))
199 {
200     UNUSED_PARAM(registrationDatabaseDirectory);
201     allServers().add(this);
202     m_taskThread = Thread::create(ASCIILiteral("ServiceWorker Task Thread"), [this] {
203         taskThreadEntryPoint();
204     });
205 }
206
207 // https://w3c.github.io/ServiceWorker/#schedule-job-algorithm
208 void SWServer::scheduleJob(const ServiceWorkerJobData& jobData)
209 {
210     ASSERT(m_connections.contains(jobData.connectionIdentifier()));
211
212     // FIXME: Per the spec, check if this job is equivalent to the last job on the queue.
213     // If it is, stack it along with that job.
214
215     auto& jobQueue = *m_jobQueues.ensure(jobData.registrationKey(), [this, &jobData] {
216         return std::make_unique<SWServerJobQueue>(*this, jobData.registrationKey());
217     }).iterator->value;
218
219     jobQueue.enqueueJob(jobData);
220     if (jobQueue.size() == 1)
221         jobQueue.runNextJob();
222 }
223
224 void SWServer::rejectJob(const ServiceWorkerJobData& jobData, const ExceptionData& exceptionData)
225 {
226     LOG(ServiceWorker, "Rejected ServiceWorker job %s in server", jobData.identifier().loggingString().utf8().data());
227     auto* connection = m_connections.get(jobData.connectionIdentifier());
228     if (!connection)
229         return;
230
231     connection->rejectJobInClient(jobData.identifier(), exceptionData);
232 }
233
234 void SWServer::resolveRegistrationJob(const ServiceWorkerJobData& jobData, const ServiceWorkerRegistrationData& registrationData, ShouldNotifyWhenResolved shouldNotifyWhenResolved)
235 {
236     LOG(ServiceWorker, "Resolved ServiceWorker job %s in server with registration %s", jobData.identifier().loggingString().utf8().data(), registrationData.identifier.loggingString().utf8().data());
237     auto* connection = m_connections.get(jobData.connectionIdentifier());
238     if (!connection)
239         return;
240
241     connection->resolveRegistrationJobInClient(jobData.identifier(), registrationData, shouldNotifyWhenResolved);
242 }
243
244 void SWServer::resolveUnregistrationJob(const ServiceWorkerJobData& jobData, const ServiceWorkerRegistrationKey& registrationKey, bool unregistrationResult)
245 {
246     auto* connection = m_connections.get(jobData.connectionIdentifier());
247     if (!connection)
248         return;
249
250     connection->resolveUnregistrationJobInClient(jobData.identifier(), registrationKey, unregistrationResult);
251 }
252
253 void SWServer::startScriptFetch(const ServiceWorkerJobData& jobData)
254 {
255     LOG(ServiceWorker, "Server issuing startScriptFetch for current job %s in client", jobData.identifier().loggingString().utf8().data());
256     auto* connection = m_connections.get(jobData.connectionIdentifier());
257     if (!connection)
258         return;
259
260     connection->startScriptFetchInClient(jobData.identifier());
261 }
262
263 void SWServer::scriptFetchFinished(Connection& connection, const ServiceWorkerFetchResult& result)
264 {
265     LOG(ServiceWorker, "Server handling scriptFetchFinished for current job %s in client", result.jobDataIdentifier.loggingString().utf8().data());
266
267     ASSERT(m_connections.contains(result.jobDataIdentifier.connectionIdentifier));
268
269     auto jobQueue = m_jobQueues.get(result.registrationKey);
270     if (!jobQueue)
271         return;
272
273     jobQueue->scriptFetchFinished(connection, result);
274 }
275
276 void SWServer::scriptContextFailedToStart(const std::optional<ServiceWorkerJobDataIdentifier>& jobDataIdentifier, SWServerWorker& worker, const String& message)
277 {
278     if (!jobDataIdentifier)
279         return;
280
281     if (auto* jobQueue = m_jobQueues.get(worker.registrationKey()))
282         jobQueue->scriptContextFailedToStart(*jobDataIdentifier, worker.identifier(), message);
283 }
284
285 void SWServer::scriptContextStarted(const std::optional<ServiceWorkerJobDataIdentifier>& jobDataIdentifier, SWServerWorker& worker)
286 {
287     if (!jobDataIdentifier)
288         return;
289
290     if (auto* jobQueue = m_jobQueues.get(worker.registrationKey()))
291         jobQueue->scriptContextStarted(*jobDataIdentifier, worker.identifier());
292 }
293
294 void SWServer::didFinishInstall(const std::optional<ServiceWorkerJobDataIdentifier>& jobDataIdentifier, SWServerWorker& worker, bool wasSuccessful)
295 {
296     if (!jobDataIdentifier)
297         return;
298
299     if (auto* jobQueue = m_jobQueues.get(worker.registrationKey()))
300         jobQueue->didFinishInstall(*jobDataIdentifier, worker.identifier(), wasSuccessful);
301 }
302
303 void SWServer::didFinishActivation(SWServerWorker& worker)
304 {
305     if (auto* registration = getRegistration(worker.registrationKey()))
306         registration->didFinishActivation(worker.identifier());
307 }
308
309 // https://w3c.github.io/ServiceWorker/#clients-get
310 std::optional<ServiceWorkerClientData> SWServer::findClientByIdentifier(const ClientOrigin& origin, ServiceWorkerClientIdentifier clientIdentifier)
311 {
312     // FIXME: Support WindowClient additional properties.
313
314     auto iterator = m_clients.find(origin);
315     if (iterator == m_clients.end())
316         return std::nullopt;
317
318     auto& clients = iterator->value.clients;
319     auto position = clients.findMatching([&] (const auto& client) {
320         return clientIdentifier == client.identifier;
321     });
322
323     return (position != notFound) ? std::make_optional(clients[position].data) : std::nullopt;
324 }
325
326 // https://w3c.github.io/ServiceWorker/#clients-getall
327 void SWServer::matchAll(SWServerWorker& worker, const ServiceWorkerClientQueryOptions& options, ServiceWorkerClientsMatchAllCallback&& callback)
328 {
329     // FIXME: Support reserved client filtering.
330     // FIXME: Support WindowClient additional properties.
331
332     auto clients = m_clients.find(worker.origin())->value.clients;
333
334     if (!options.includeUncontrolled) {
335         clients.removeAllMatching([&] (const auto& client) {
336             return worker.identifier() != m_clientToControllingWorker.get(client.identifier);
337         });
338     }
339     if (options.type != ServiceWorkerClientType::All) {
340         clients.removeAllMatching([&] (const auto& client) {
341             return options.type != client.data.type;
342         });
343     }
344     callback(WTFMove(clients));
345 }
346
347 void SWServer::didResolveRegistrationPromise(Connection& connection, const ServiceWorkerRegistrationKey& registrationKey)
348 {
349     ASSERT_UNUSED(connection, m_connections.contains(connection.identifier()));
350
351     if (auto* jobQueue = m_jobQueues.get(registrationKey))
352         jobQueue->didResolveRegistrationPromise();
353 }
354
355 void SWServer::addClientServiceWorkerRegistration(Connection& connection, ServiceWorkerRegistrationIdentifier identifier)
356 {
357     auto* registration = m_registrationsByID.get(identifier);
358     if (!registration) {
359         LOG_ERROR("Request to add client-side ServiceWorkerRegistration to non-existent server-side registration");
360         return;
361     }
362     
363     registration->addClientServiceWorkerRegistration(connection.identifier());
364 }
365
366 void SWServer::removeClientServiceWorkerRegistration(Connection& connection, ServiceWorkerRegistrationIdentifier identifier)
367 {
368     auto* registration = m_registrationsByID.get(identifier);
369     if (!registration) {
370         LOG_ERROR("Request to remove client-side ServiceWorkerRegistration from non-existent server-side registration");
371         return;
372     }
373     
374     registration->removeClientServiceWorkerRegistration(connection.identifier());
375 }
376
377 void SWServer::updateWorker(Connection&, const ServiceWorkerJobDataIdentifier& jobDataIdentifier, SWServerRegistration& registration, const URL& url, const String& script, WorkerType type)
378 {
379     auto serviceWorkerIdentifier = generateServiceWorkerIdentifier();
380
381     ServiceWorkerContextData data = { jobDataIdentifier, registration.data(), serviceWorkerIdentifier, script, url, type };
382
383     // Right now we only ever keep up to one connection to one SW context process.
384     // And it should always exist if we're calling updateWorker
385     auto* connection = SWServerToContextConnection::globalServerToContextConnection();
386     if (!connection) {
387         m_pendingContextDatas.append(WTFMove(data));
388         return;
389     }
390     
391     installContextData(data);
392 }
393
394 void SWServer::serverToContextConnectionCreated()
395 {
396     ASSERT(SWServerToContextConnection::globalServerToContextConnection());
397     for (auto& data : m_pendingContextDatas)
398         installContextData(data);
399     
400     m_pendingContextDatas.clear();
401 }
402
403 void SWServer::installContextData(const ServiceWorkerContextData& data)
404 {
405     auto* connection = SWServerToContextConnection::globalServerToContextConnection();
406     ASSERT(connection);
407
408     auto* registration = m_registrations.get(data.registration.key);
409     RELEASE_ASSERT(registration);
410
411     auto result = m_runningOrTerminatingWorkers.add(data.serviceWorkerIdentifier, SWServerWorker::create(*this, *registration, connection->identifier(), data.scriptURL, data.script, data.workerType, data.serviceWorkerIdentifier));
412     ASSERT(result.isNewEntry);
413
414     result.iterator->value->setState(SWServerWorker::State::Running);
415
416     connection->installServiceWorkerContext(data);
417 }
418
419 bool SWServer::invokeRunServiceWorker(ServiceWorkerIdentifier identifier)
420 {
421     if (auto* worker = m_runningOrTerminatingWorkers.get(identifier)) {
422         if (worker->isRunning())
423             return true;
424     }
425
426     // Nobody should have a ServiceWorkerIdentifier for a SWServerWorker that doesn't exist.
427     auto* worker = workerByID(identifier);
428     ASSERT(worker);
429
430     // If the registration for a working has been removed then the request to run
431     // the worker is moot.
432     if (!getRegistration(worker->registrationKey()))
433         return false;
434
435     m_runningOrTerminatingWorkers.add(identifier, *worker);
436     worker->setState(SWServerWorker::State::Running);
437
438     auto* connection = SWServerToContextConnection::globalServerToContextConnection();
439     ASSERT(connection);
440     connection->installServiceWorkerContext(worker->contextData());
441     
442     return true;
443 }
444
445 void SWServer::terminateWorker(SWServerWorker& worker)
446 {
447     terminateWorkerInternal(worker, Asynchronous);
448 }
449
450 void SWServer::syncTerminateWorker(SWServerWorker& worker)
451 {
452     terminateWorkerInternal(worker, Synchronous);
453 }
454
455 void SWServer::terminateWorkerInternal(SWServerWorker& worker, TerminationMode mode)
456 {
457     auto* connection = SWServerToContextConnection::connectionForIdentifier(worker.contextConnectionIdentifier());
458     if (!connection) {
459         LOG_ERROR("Request to terminate a worker whose context connection does not exist");
460         return;
461     }
462
463     ASSERT(m_runningOrTerminatingWorkers.get(worker.identifier()) == &worker);
464     ASSERT(!worker.isTerminating());
465
466     worker.setState(SWServerWorker::State::Terminating);
467
468     switch (mode) {
469     case Asynchronous:
470         connection->terminateWorker(worker.identifier());
471         break;
472     case Synchronous:
473         connection->syncTerminateWorker(worker.identifier());
474         break;
475     };
476 }
477
478 void SWServer::workerContextTerminated(SWServerWorker& worker)
479 {
480     ASSERT(worker.isTerminating());
481
482     worker.setState(SWServerWorker::State::NotRunning);
483
484     // At this point if no registrations are referencing the worker then it will be destroyed,
485     // removing itself from the m_workersByID map.
486     auto result = m_runningOrTerminatingWorkers.take(worker.identifier());
487     ASSERT_UNUSED(result, result && result->ptr() == &worker);
488 }
489
490 void SWServer::fireInstallEvent(SWServerWorker& worker)
491 {
492     auto* connection = SWServerToContextConnection::connectionForIdentifier(worker.contextConnectionIdentifier());
493     if (!connection) {
494         LOG_ERROR("Request to fire install event on a worker whose context connection does not exist");
495         return;
496     }
497
498     connection->fireInstallEvent(worker.identifier());
499 }
500
501 void SWServer::fireActivateEvent(SWServerWorker& worker)
502 {
503     auto* connection = SWServerToContextConnection::connectionForIdentifier(worker.contextConnectionIdentifier());
504     if (!connection) {
505         LOG_ERROR("Request to fire install event on a worker whose context connection does not exist");
506         return;
507     }
508
509     connection->fireActivateEvent(worker.identifier());
510 }
511
512 void SWServer::taskThreadEntryPoint()
513 {
514     ASSERT(!isMainThread());
515
516     while (!m_taskQueue.isKilled())
517         m_taskQueue.waitForMessage().performTask();
518
519     Locker<Lock> locker(m_taskThreadLock);
520     m_taskThread = nullptr;
521 }
522
523 void SWServer::postTask(CrossThreadTask&& task)
524 {
525     m_taskQueue.append(WTFMove(task));
526 }
527
528 void SWServer::postTaskReply(CrossThreadTask&& task)
529 {
530     m_taskReplyQueue.append(WTFMove(task));
531
532     Locker<Lock> locker(m_mainThreadReplyLock);
533     if (m_mainThreadReplyScheduled)
534         return;
535
536     m_mainThreadReplyScheduled = true;
537     callOnMainThread([this] {
538         handleTaskRepliesOnMainThread();
539     });
540 }
541
542 void SWServer::handleTaskRepliesOnMainThread()
543 {
544     {
545         Locker<Lock> locker(m_mainThreadReplyLock);
546         m_mainThreadReplyScheduled = false;
547     }
548
549     while (auto task = m_taskReplyQueue.tryGetMessage())
550         task->performTask();
551 }
552
553 void SWServer::registerConnection(Connection& connection)
554 {
555     auto result = m_connections.add(connection.identifier(), nullptr);
556     ASSERT(result.isNewEntry);
557     result.iterator->value = &connection;
558 }
559
560 void SWServer::unregisterConnection(Connection& connection)
561 {
562     ASSERT(m_connections.get(connection.identifier()) == &connection);
563     m_connections.remove(connection.identifier());
564
565     for (auto& registration : m_registrations.values())
566         registration->unregisterServerConnection(connection.identifier());
567 }
568
569 const SWServerRegistration* SWServer::doRegistrationMatching(const SecurityOriginData& topOrigin, const URL& clientURL) const
570 {
571     const SWServerRegistration* selectedRegistration = nullptr;
572     for (auto& registration : m_registrations.values()) {
573         if (!registration->key().isMatching(topOrigin, clientURL))
574             continue;
575         if (!selectedRegistration || selectedRegistration->key().scopeLength() < registration->key().scopeLength())
576             selectedRegistration = registration.get();
577     }
578
579     return (selectedRegistration && !selectedRegistration->isUninstalling()) ? selectedRegistration : nullptr;
580 }
581
582 void SWServer::setClientActiveWorker(ServiceWorkerClientIdentifier clientIdentifier, ServiceWorkerIdentifier serviceWorkerIdentifier)
583 {
584     m_clientToControllingWorker.set(clientIdentifier, serviceWorkerIdentifier);
585 }
586
587 SWServerRegistration* SWServer::registrationFromServiceWorkerIdentifier(ServiceWorkerIdentifier identifier)
588 {
589     auto iterator = m_runningOrTerminatingWorkers.find(identifier);
590     if (iterator == m_runningOrTerminatingWorkers.end())
591         return nullptr;
592
593     return m_registrations.get(iterator->value->registrationKey());
594 }
595
596 void SWServer::registerServiceWorkerClient(ClientOrigin&& clientOrigin, ServiceWorkerClientIdentifier clientIdentifier, ServiceWorkerClientData&& data, const std::optional<ServiceWorkerIdentifier>& controllingServiceWorkerIdentifier)
597 {
598     auto& clientsData = m_clients.ensure(WTFMove(clientOrigin), [] {
599         return Clients { };
600     }).iterator->value;
601
602     clientsData.clients.append(ServiceWorkerClientInformation { clientIdentifier, WTFMove(data) });
603     if (clientsData.terminateServiceWorkersTimer)
604         clientsData.terminateServiceWorkersTimer = nullptr;
605
606     if (!controllingServiceWorkerIdentifier)
607         return;
608
609     if (auto* controllingRegistration = registrationFromServiceWorkerIdentifier(*controllingServiceWorkerIdentifier)) {
610         controllingRegistration->addClientUsingRegistration(clientIdentifier);
611         auto result = m_clientToControllingWorker.add(clientIdentifier, *controllingServiceWorkerIdentifier);
612         ASSERT_UNUSED(result, result.isNewEntry);
613     }
614 }
615
616 void SWServer::unregisterServiceWorkerClient(const ClientOrigin& clientOrigin, ServiceWorkerClientIdentifier clientIdentifier)
617 {
618     auto clientIterator = m_clients.find(clientOrigin);
619     ASSERT(clientIterator != m_clients.end());
620
621     auto& clients = clientIterator->value.clients;
622     clients.removeFirstMatching([&] (const auto& client) {
623         return clientIdentifier == client.identifier;
624     });
625     if (clients.isEmpty()) {
626         ASSERT(!clientIterator->value.terminateServiceWorkersTimer);
627         clientIterator->value.terminateServiceWorkersTimer = std::make_unique<Timer>([clientOrigin, this] {
628             for (auto& worker : m_runningOrTerminatingWorkers.values()) {
629                 if (worker->origin() == clientOrigin)
630                     terminateWorker(worker);
631             }
632             m_clients.remove(clientOrigin);
633         });
634         clientIterator->value.terminateServiceWorkersTimer->startOneShot(terminationDelay);
635     }
636
637     auto workerIterator = m_clientToControllingWorker.find(clientIdentifier);
638     if (workerIterator == m_clientToControllingWorker.end())
639         return;
640
641     if (auto* controllingRegistration = registrationFromServiceWorkerIdentifier(workerIterator->value))
642         controllingRegistration->removeClientUsingRegistration(clientIdentifier);
643
644     m_clientToControllingWorker.remove(workerIterator);
645 }
646
647 void SWServer::resolveRegistrationReadyRequests(SWServerRegistration& registration)
648 {
649     for (auto* connection : m_connections.values())
650         connection->resolveRegistrationReadyRequests(registration);
651 }
652
653 void SWServer::Connection::whenRegistrationReady(uint64_t registrationReadyRequestIdentifier, const SecurityOriginData& topOrigin, const URL& clientURL)
654 {
655     if (auto* registration = doRegistrationMatching(topOrigin, clientURL)) {
656         if (registration->activeWorker()) {
657             registrationReady(registrationReadyRequestIdentifier, registration->data());
658             return;
659         }
660     }
661     m_registrationReadyRequests.append({ topOrigin, clientURL, registrationReadyRequestIdentifier });
662 }
663
664 void SWServer::Connection::resolveRegistrationReadyRequests(SWServerRegistration& registration)
665 {
666     m_registrationReadyRequests.removeAllMatching([&](auto& request) {
667         if (!registration.key().isMatching(request.topOrigin, request.clientURL))
668             return false;
669
670         registrationReady(request.identifier, registration.data());
671         return true;
672     });
673 }
674
675 } // namespace WebCore
676
677 #endif // ENABLE(SERVICE_WORKER)