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