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