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