2 * Copyright (C) 2017 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
29 #if ENABLE(SERVICE_WORKER)
31 #include "ExceptionCode.h"
32 #include "ExceptionData.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>
51 static Seconds terminationDelay { 10_s };
53 SWServer::Connection::Connection(SWServer& server)
55 , m_identifier(generateObjectIdentifier<SWServerConnectionIdentifierType>())
57 m_server.registerConnection(*this);
60 SWServer::Connection::~Connection()
62 m_server.unregisterConnection(*this);
65 HashSet<SWServer*>& SWServer::allServers()
67 static NeverDestroyed<HashSet<SWServer*>> servers;
73 RELEASE_ASSERT(m_connections.isEmpty());
74 RELEASE_ASSERT(m_registrations.isEmpty());
75 RELEASE_ASSERT(m_jobQueues.isEmpty());
77 ASSERT(m_taskQueue.isEmpty());
78 ASSERT(m_taskReplyQueue.isEmpty());
80 // For a SWServer to be cleanly shut down its thread must have finished and gone away.
81 // At this stage in development of the feature that actually never happens.
82 // But once it does start happening, this ASSERT will catch us doing it wrong.
83 Locker<Lock> locker(m_taskThreadLock);
84 ASSERT(!m_taskThread);
86 allServers().remove(this);
89 SWServerWorker* SWServer::workerByID(ServiceWorkerIdentifier identifier) const
91 auto* worker = SWServerWorker::existingWorkerForIdentifier(identifier);
92 ASSERT(!worker || &worker->server() == this);
96 SWServerRegistration* SWServer::getRegistration(const ServiceWorkerRegistrationKey& registrationKey)
98 return m_registrations.get(registrationKey);
101 void SWServer::registrationStoreImportComplete()
103 m_originStore->importComplete();
106 void SWServer::addRegistrationFromStore(ServiceWorkerContextData&& data)
108 // Pages should not have been able to make a new registration to this key while the import was still taking place.
109 ASSERT(!m_registrations.contains(data.registration.key));
111 addRegistration(std::make_unique<SWServerRegistration>(*this, data.registration.key, data.registration.updateViaCache, data.registration.scopeURL, data.scriptURL));
112 tryInstallContextData(WTFMove(data));
115 void SWServer::addRegistration(std::unique_ptr<SWServerRegistration>&& registration)
117 auto key = registration->key();
118 auto* registrationPtr = registration.get();
119 auto addResult1 = m_registrations.add(key, WTFMove(registration));
120 ASSERT_UNUSED(addResult1, addResult1.isNewEntry);
122 auto addResult2 = m_registrationsByID.add(registrationPtr->identifier(), registrationPtr);
123 ASSERT_UNUSED(addResult2, addResult2.isNewEntry);
125 m_originStore->add(key.topOrigin().securityOrigin());
128 void SWServer::removeRegistration(const ServiceWorkerRegistrationKey& key)
130 auto topOrigin = key.topOrigin().securityOrigin();
131 auto registration = m_registrations.take(key);
132 ASSERT(registration);
133 bool wasRemoved = m_registrationsByID.remove(registration->identifier());
134 ASSERT_UNUSED(wasRemoved, wasRemoved);
136 m_originStore->remove(topOrigin);
137 m_registrationStore.removeRegistration(*registration);
140 Vector<ServiceWorkerRegistrationData> SWServer::getRegistrations(const SecurityOriginData& topOrigin, const URL& clientURL)
142 Vector<SWServerRegistration*> matchingRegistrations;
143 for (auto& item : m_registrations) {
144 if (!item.value->isUninstalling() && item.key.originIsMatching(topOrigin, clientURL))
145 matchingRegistrations.append(item.value.get());
147 // The specification mandates that registrations are returned in the insertion order.
148 std::sort(matchingRegistrations.begin(), matchingRegistrations.end(), [](auto& a, auto& b) {
149 return a->creationTime() < b->creationTime();
151 Vector<ServiceWorkerRegistrationData> matchingRegistrationDatas;
152 matchingRegistrationDatas.reserveInitialCapacity(matchingRegistrations.size());
153 for (auto* registration : matchingRegistrations)
154 matchingRegistrationDatas.uncheckedAppend(registration->data());
155 return matchingRegistrationDatas;
158 void SWServer::clearAll(WTF::CompletionHandler<void()>&& completionHandler)
161 while (!m_registrations.isEmpty())
162 m_registrations.begin()->value->clear();
163 ASSERT(m_registrationsByID.isEmpty());
164 m_originStore->clearAll();
165 m_registrationStore.clearAll(WTFMove(completionHandler));
168 void SWServer::clear(const SecurityOrigin& origin, WTF::CompletionHandler<void()>&& completionHandler)
170 m_jobQueues.removeIf([&](auto& keyAndValue) {
171 return keyAndValue.key.relatesToOrigin(origin);
174 Vector<SWServerRegistration*> registrationsToRemove;
175 for (auto& keyAndValue : m_registrations) {
176 if (keyAndValue.key.relatesToOrigin(origin))
177 registrationsToRemove.append(keyAndValue.value.get());
180 // Calling SWServerRegistration::clear() takes care of updating m_registrations, m_originStore and m_registrationStore.
181 for (auto* registration : registrationsToRemove)
182 registration->clear();
184 m_registrationStore.flushChanges(WTFMove(completionHandler));
187 void SWServer::Connection::scheduleJobInServer(const ServiceWorkerJobData& jobData)
189 LOG(ServiceWorker, "Scheduling ServiceWorker job %s in server", jobData.identifier().loggingString().utf8().data());
190 ASSERT(identifier() == jobData.connectionIdentifier());
192 m_server.scheduleJob(jobData);
195 void SWServer::Connection::finishFetchingScriptInServer(const ServiceWorkerFetchResult& result)
197 m_server.scriptFetchFinished(*this, result);
200 void SWServer::Connection::didResolveRegistrationPromise(const ServiceWorkerRegistrationKey& key)
202 m_server.didResolveRegistrationPromise(*this, key);
205 void SWServer::Connection::addServiceWorkerRegistrationInServer(ServiceWorkerRegistrationIdentifier identifier)
207 m_server.addClientServiceWorkerRegistration(*this, identifier);
210 void SWServer::Connection::removeServiceWorkerRegistrationInServer(ServiceWorkerRegistrationIdentifier identifier)
212 m_server.removeClientServiceWorkerRegistration(*this, identifier);
215 void SWServer::Connection::syncTerminateWorker(ServiceWorkerIdentifier identifier)
217 if (auto* worker = m_server.workerByID(identifier))
218 m_server.syncTerminateWorker(*worker);
221 SWServer::SWServer(UniqueRef<SWOriginStore>&& originStore, String&& registrationDatabaseDirectory, PAL::SessionID sessionID)
222 : m_originStore(WTFMove(originStore))
223 , m_registrationStore(*this, WTFMove(registrationDatabaseDirectory))
224 , m_sessionID(sessionID)
226 UNUSED_PARAM(registrationDatabaseDirectory);
227 allServers().add(this);
228 m_taskThread = Thread::create(ASCIILiteral("ServiceWorker Task Thread"), [this] {
229 taskThreadEntryPoint();
233 // https://w3c.github.io/ServiceWorker/#schedule-job-algorithm
234 void SWServer::scheduleJob(const ServiceWorkerJobData& jobData)
236 ASSERT(m_connections.contains(jobData.connectionIdentifier()));
238 // FIXME: Per the spec, check if this job is equivalent to the last job on the queue.
239 // If it is, stack it along with that job.
241 auto& jobQueue = *m_jobQueues.ensure(jobData.registrationKey(), [this, &jobData] {
242 return std::make_unique<SWServerJobQueue>(*this, jobData.registrationKey());
245 jobQueue.enqueueJob(jobData);
246 if (jobQueue.size() == 1)
247 jobQueue.runNextJob();
250 void SWServer::rejectJob(const ServiceWorkerJobData& jobData, const ExceptionData& exceptionData)
252 LOG(ServiceWorker, "Rejected ServiceWorker job %s in server", jobData.identifier().loggingString().utf8().data());
253 auto* connection = m_connections.get(jobData.connectionIdentifier());
257 connection->rejectJobInClient(jobData.identifier(), exceptionData);
260 void SWServer::resolveRegistrationJob(const ServiceWorkerJobData& jobData, const ServiceWorkerRegistrationData& registrationData, ShouldNotifyWhenResolved shouldNotifyWhenResolved)
262 LOG(ServiceWorker, "Resolved ServiceWorker job %s in server with registration %s", jobData.identifier().loggingString().utf8().data(), registrationData.identifier.loggingString().utf8().data());
263 auto* connection = m_connections.get(jobData.connectionIdentifier());
267 connection->resolveRegistrationJobInClient(jobData.identifier(), registrationData, shouldNotifyWhenResolved);
270 void SWServer::resolveUnregistrationJob(const ServiceWorkerJobData& jobData, const ServiceWorkerRegistrationKey& registrationKey, bool unregistrationResult)
272 auto* connection = m_connections.get(jobData.connectionIdentifier());
276 connection->resolveUnregistrationJobInClient(jobData.identifier(), registrationKey, unregistrationResult);
279 void SWServer::startScriptFetch(const ServiceWorkerJobData& jobData)
281 LOG(ServiceWorker, "Server issuing startScriptFetch for current job %s in client", jobData.identifier().loggingString().utf8().data());
282 auto* connection = m_connections.get(jobData.connectionIdentifier());
286 connection->startScriptFetchInClient(jobData.identifier());
289 void SWServer::scriptFetchFinished(Connection& connection, const ServiceWorkerFetchResult& result)
291 LOG(ServiceWorker, "Server handling scriptFetchFinished for current job %s in client", result.jobDataIdentifier.loggingString().utf8().data());
293 ASSERT(m_connections.contains(result.jobDataIdentifier.connectionIdentifier));
295 auto jobQueue = m_jobQueues.get(result.registrationKey);
299 jobQueue->scriptFetchFinished(connection, result);
302 void SWServer::scriptContextFailedToStart(const std::optional<ServiceWorkerJobDataIdentifier>& jobDataIdentifier, SWServerWorker& worker, const String& message)
304 if (!jobDataIdentifier)
307 if (auto* jobQueue = m_jobQueues.get(worker.registrationKey()))
308 jobQueue->scriptContextFailedToStart(*jobDataIdentifier, worker.identifier(), message);
311 void SWServer::scriptContextStarted(const std::optional<ServiceWorkerJobDataIdentifier>& jobDataIdentifier, SWServerWorker& worker)
313 if (!jobDataIdentifier)
316 if (auto* jobQueue = m_jobQueues.get(worker.registrationKey()))
317 jobQueue->scriptContextStarted(*jobDataIdentifier, worker.identifier());
320 void SWServer::didFinishInstall(const std::optional<ServiceWorkerJobDataIdentifier>& jobDataIdentifier, SWServerWorker& worker, bool wasSuccessful)
322 if (!jobDataIdentifier)
325 if (auto* jobQueue = m_jobQueues.get(worker.registrationKey()))
326 jobQueue->didFinishInstall(*jobDataIdentifier, worker.identifier(), wasSuccessful);
329 void SWServer::didFinishActivation(SWServerWorker& worker)
331 if (auto* registration = getRegistration(worker.registrationKey()))
332 registration->didFinishActivation(worker.identifier());
335 // https://w3c.github.io/ServiceWorker/#clients-get
336 std::optional<ServiceWorkerClientData> SWServer::findClientByIdentifier(const ClientOrigin& origin, ServiceWorkerClientIdentifier clientIdentifier)
338 // FIXME: Support WindowClient additional properties.
340 auto iterator = m_clients.find(origin);
341 if (iterator == m_clients.end())
344 auto& clients = iterator->value.clients;
345 auto position = clients.findMatching([&] (const auto& client) {
346 return clientIdentifier == client.identifier;
349 return (position != notFound) ? std::make_optional(clients[position].data) : std::nullopt;
352 // https://w3c.github.io/ServiceWorker/#clients-getall
353 void SWServer::matchAll(SWServerWorker& worker, const ServiceWorkerClientQueryOptions& options, ServiceWorkerClientsMatchAllCallback&& callback)
355 // FIXME: Support reserved client filtering.
356 // FIXME: Support WindowClient additional properties.
358 auto clients = m_clients.find(worker.origin())->value.clients;
360 if (!options.includeUncontrolled) {
361 clients.removeAllMatching([&] (const auto& client) {
362 return worker.identifier() != m_clientToControllingWorker.get(client.identifier);
365 if (options.type != ServiceWorkerClientType::All) {
366 clients.removeAllMatching([&] (const auto& client) {
367 return options.type != client.data.type;
370 callback(WTFMove(clients));
373 void SWServer::claim(SWServerWorker& worker)
375 auto& origin = worker.origin();
376 auto iterator = m_clients.find(origin);
377 if (iterator == m_clients.end())
380 auto& clients = iterator->value.clients;
381 for (auto& client : clients) {
382 auto* registration = doRegistrationMatching(origin.topOrigin, client.data.url);
383 if (!(registration && registration->key() == worker.registrationKey()))
386 auto result = m_clientToControllingWorker.add(client.identifier, worker.identifier());
387 if (!result.isNewEntry) {
388 if (result.iterator->value == worker.identifier())
390 if (auto* controllingRegistration = registrationFromServiceWorkerIdentifier(result.iterator->value))
391 controllingRegistration->removeClientUsingRegistration(client.identifier);
392 result.iterator->value = worker.identifier();
394 registration->controlClient(client.identifier);
398 void SWServer::didResolveRegistrationPromise(Connection& connection, const ServiceWorkerRegistrationKey& registrationKey)
400 ASSERT_UNUSED(connection, m_connections.contains(connection.identifier()));
402 if (auto* jobQueue = m_jobQueues.get(registrationKey))
403 jobQueue->didResolveRegistrationPromise();
406 void SWServer::addClientServiceWorkerRegistration(Connection& connection, ServiceWorkerRegistrationIdentifier identifier)
408 auto* registration = m_registrationsByID.get(identifier);
410 LOG_ERROR("Request to add client-side ServiceWorkerRegistration to non-existent server-side registration");
414 registration->addClientServiceWorkerRegistration(connection.identifier());
417 void SWServer::removeClientServiceWorkerRegistration(Connection& connection, ServiceWorkerRegistrationIdentifier identifier)
419 auto* registration = m_registrationsByID.get(identifier);
421 LOG_ERROR("Request to remove client-side ServiceWorkerRegistration from non-existent server-side registration");
425 registration->removeClientServiceWorkerRegistration(connection.identifier());
428 void SWServer::updateWorker(Connection&, const ServiceWorkerJobDataIdentifier& jobDataIdentifier, SWServerRegistration& registration, const URL& url, const String& script, WorkerType type)
430 registration.setLastUpdateTime(WallTime::now());
431 tryInstallContextData({ jobDataIdentifier, registration.data(), generateObjectIdentifier<ServiceWorkerIdentifierType>(), script, url, type, false });
434 void SWServer::tryInstallContextData(ServiceWorkerContextData&& data)
436 // Right now we only ever keep up to one connection to one SW context process.
437 // And it should always exist if we're trying to install context data.
438 auto* connection = SWServerToContextConnection::globalServerToContextConnection();
440 m_pendingContextDatas.append(WTFMove(data));
444 installContextData(data);
447 void SWServer::serverToContextConnectionCreated()
449 auto* connection = SWServerToContextConnection::globalServerToContextConnection();
452 auto pendingContextDatas = WTFMove(m_pendingContextDatas);
453 for (auto& data : pendingContextDatas)
454 installContextData(data);
456 auto serviceWorkerRunRequests = WTFMove(m_serviceWorkerRunRequests);
457 for (auto& item : serviceWorkerRunRequests) {
458 bool success = runServiceWorker(item.key);
459 for (auto& callback : item.value)
460 callback(success, *connection);
464 void SWServer::installContextData(const ServiceWorkerContextData& data)
466 if (!data.loadedFromDisk)
467 m_registrationStore.updateRegistration(data);
469 auto* connection = SWServerToContextConnection::globalServerToContextConnection();
472 auto* registration = m_registrations.get(data.registration.key);
473 RELEASE_ASSERT(registration);
475 auto worker = SWServerWorker::create(*this, *registration, connection->identifier(), data.scriptURL, data.script, data.workerType, data.serviceWorkerIdentifier);
477 // We don't immediately launch all workers that were just read in from disk,
478 // as it is unlikely they will be needed immediately.
479 if (data.loadedFromDisk) {
480 registration->updateRegistrationState(ServiceWorkerRegistrationState::Active, worker.ptr());
484 worker->setState(SWServerWorker::State::Running);
485 auto result = m_runningOrTerminatingWorkers.add(data.serviceWorkerIdentifier, WTFMove(worker));
486 ASSERT_UNUSED(result, result.isNewEntry);
488 connection->installServiceWorkerContext(data, m_sessionID);
491 void SWServer::runServiceWorkerIfNecessary(ServiceWorkerIdentifier identifier, RunServiceWorkerCallback&& callback)
493 auto* connection = SWServerToContextConnection::globalServerToContextConnection();
494 if (auto* worker = m_runningOrTerminatingWorkers.get(identifier)) {
495 if (worker->isRunning()) {
497 callback(true, *connection);
503 m_serviceWorkerRunRequests.ensure(identifier, [&] {
504 return Vector<RunServiceWorkerCallback> { };
505 }).iterator->value.append(WTFMove(callback));
509 callback(runServiceWorker(identifier), *connection);
512 bool SWServer::runServiceWorker(ServiceWorkerIdentifier identifier)
514 auto* worker = workerByID(identifier);
518 // If the registration for a working has been removed then the request to run
519 // the worker is moot.
520 if (!getRegistration(worker->registrationKey()))
523 auto addResult = m_runningOrTerminatingWorkers.add(identifier, *worker);
524 ASSERT_UNUSED(addResult, addResult.isNewEntry);
526 worker->setState(SWServerWorker::State::Running);
528 auto* connection = SWServerToContextConnection::globalServerToContextConnection();
530 connection->installServiceWorkerContext(worker->contextData(), m_sessionID);
535 void SWServer::terminateWorker(SWServerWorker& worker)
537 terminateWorkerInternal(worker, Asynchronous);
540 void SWServer::syncTerminateWorker(SWServerWorker& worker)
542 terminateWorkerInternal(worker, Synchronous);
545 void SWServer::terminateWorkerInternal(SWServerWorker& worker, TerminationMode mode)
547 auto* connection = SWServerToContextConnection::connectionForIdentifier(worker.contextConnectionIdentifier());
549 LOG_ERROR("Request to terminate a worker whose context connection does not exist");
553 ASSERT(m_runningOrTerminatingWorkers.get(worker.identifier()) == &worker);
554 ASSERT(!worker.isTerminating());
556 worker.setState(SWServerWorker::State::Terminating);
560 connection->terminateWorker(worker.identifier());
563 connection->syncTerminateWorker(worker.identifier());
568 void SWServer::markAllWorkersAsTerminated()
570 while (!m_runningOrTerminatingWorkers.isEmpty())
571 workerContextTerminated(m_runningOrTerminatingWorkers.begin()->value);
574 void SWServer::workerContextTerminated(SWServerWorker& worker)
576 worker.setState(SWServerWorker::State::NotRunning);
578 // At this point if no registrations are referencing the worker then it will be destroyed,
579 // removing itself from the m_workersByID map.
580 auto result = m_runningOrTerminatingWorkers.take(worker.identifier());
581 ASSERT_UNUSED(result, result && result->ptr() == &worker);
584 void SWServer::fireInstallEvent(SWServerWorker& worker)
586 auto* connection = SWServerToContextConnection::connectionForIdentifier(worker.contextConnectionIdentifier());
588 LOG_ERROR("Request to fire install event on a worker whose context connection does not exist");
592 connection->fireInstallEvent(worker.identifier());
595 void SWServer::fireActivateEvent(SWServerWorker& worker)
597 auto* connection = SWServerToContextConnection::connectionForIdentifier(worker.contextConnectionIdentifier());
599 LOG_ERROR("Request to fire install event on a worker whose context connection does not exist");
603 connection->fireActivateEvent(worker.identifier());
606 void SWServer::taskThreadEntryPoint()
608 ASSERT(!isMainThread());
610 while (!m_taskQueue.isKilled())
611 m_taskQueue.waitForMessage().performTask();
613 Locker<Lock> locker(m_taskThreadLock);
614 m_taskThread = nullptr;
617 void SWServer::postTask(CrossThreadTask&& task)
619 m_taskQueue.append(WTFMove(task));
622 void SWServer::postTaskReply(CrossThreadTask&& task)
624 m_taskReplyQueue.append(WTFMove(task));
626 Locker<Lock> locker(m_mainThreadReplyLock);
627 if (m_mainThreadReplyScheduled)
630 m_mainThreadReplyScheduled = true;
631 callOnMainThread([this] {
632 handleTaskRepliesOnMainThread();
636 void SWServer::handleTaskRepliesOnMainThread()
639 Locker<Lock> locker(m_mainThreadReplyLock);
640 m_mainThreadReplyScheduled = false;
643 while (auto task = m_taskReplyQueue.tryGetMessage())
647 void SWServer::registerConnection(Connection& connection)
649 auto result = m_connections.add(connection.identifier(), nullptr);
650 ASSERT(result.isNewEntry);
651 result.iterator->value = &connection;
654 void SWServer::unregisterConnection(Connection& connection)
656 ASSERT(m_connections.get(connection.identifier()) == &connection);
657 m_connections.remove(connection.identifier());
659 for (auto& registration : m_registrations.values())
660 registration->unregisterServerConnection(connection.identifier());
663 SWServerRegistration* SWServer::doRegistrationMatching(const SecurityOriginData& topOrigin, const URL& clientURL)
665 SWServerRegistration* selectedRegistration = nullptr;
666 for (auto& registration : m_registrations.values()) {
667 if (!registration->key().isMatching(topOrigin, clientURL))
669 if (!selectedRegistration || selectedRegistration->key().scopeLength() < registration->key().scopeLength())
670 selectedRegistration = registration.get();
673 return (selectedRegistration && !selectedRegistration->isUninstalling()) ? selectedRegistration : nullptr;
676 void SWServer::setClientActiveWorker(ServiceWorkerClientIdentifier clientIdentifier, ServiceWorkerIdentifier serviceWorkerIdentifier)
678 m_clientToControllingWorker.set(clientIdentifier, serviceWorkerIdentifier);
681 SWServerRegistration* SWServer::registrationFromServiceWorkerIdentifier(ServiceWorkerIdentifier identifier)
683 auto iterator = m_runningOrTerminatingWorkers.find(identifier);
684 if (iterator == m_runningOrTerminatingWorkers.end())
687 return m_registrations.get(iterator->value->registrationKey());
690 void SWServer::registerServiceWorkerClient(ClientOrigin&& clientOrigin, ServiceWorkerClientIdentifier clientIdentifier, ServiceWorkerClientData&& data, const std::optional<ServiceWorkerIdentifier>& controllingServiceWorkerIdentifier)
692 auto& clientsData = m_clients.ensure(WTFMove(clientOrigin), [] {
696 clientsData.clients.append(ServiceWorkerClientInformation { clientIdentifier, WTFMove(data) });
697 if (clientsData.terminateServiceWorkersTimer)
698 clientsData.terminateServiceWorkersTimer = nullptr;
700 if (!controllingServiceWorkerIdentifier)
703 if (auto* controllingRegistration = registrationFromServiceWorkerIdentifier(*controllingServiceWorkerIdentifier)) {
704 controllingRegistration->addClientUsingRegistration(clientIdentifier);
705 auto result = m_clientToControllingWorker.add(clientIdentifier, *controllingServiceWorkerIdentifier);
706 ASSERT_UNUSED(result, result.isNewEntry);
710 void SWServer::unregisterServiceWorkerClient(const ClientOrigin& clientOrigin, ServiceWorkerClientIdentifier clientIdentifier)
712 auto clientIterator = m_clients.find(clientOrigin);
713 ASSERT(clientIterator != m_clients.end());
715 auto& clients = clientIterator->value.clients;
716 clients.removeFirstMatching([&] (const auto& client) {
717 return clientIdentifier == client.identifier;
719 if (clients.isEmpty()) {
720 ASSERT(!clientIterator->value.terminateServiceWorkersTimer);
721 clientIterator->value.terminateServiceWorkersTimer = std::make_unique<Timer>([clientOrigin, this] {
722 for (auto& worker : m_runningOrTerminatingWorkers.values()) {
723 if (worker->origin() == clientOrigin)
724 terminateWorker(worker);
726 m_clients.remove(clientOrigin);
728 clientIterator->value.terminateServiceWorkersTimer->startOneShot(terminationDelay);
731 auto workerIterator = m_clientToControllingWorker.find(clientIdentifier);
732 if (workerIterator == m_clientToControllingWorker.end())
735 if (auto* controllingRegistration = registrationFromServiceWorkerIdentifier(workerIterator->value))
736 controllingRegistration->removeClientUsingRegistration(clientIdentifier);
738 m_clientToControllingWorker.remove(workerIterator);
741 void SWServer::resolveRegistrationReadyRequests(SWServerRegistration& registration)
743 for (auto* connection : m_connections.values())
744 connection->resolveRegistrationReadyRequests(registration);
747 void SWServer::Connection::whenRegistrationReady(uint64_t registrationReadyRequestIdentifier, const SecurityOriginData& topOrigin, const URL& clientURL)
749 if (auto* registration = doRegistrationMatching(topOrigin, clientURL)) {
750 if (registration->activeWorker()) {
751 registrationReady(registrationReadyRequestIdentifier, registration->data());
755 m_registrationReadyRequests.append({ topOrigin, clientURL, registrationReadyRequestIdentifier });
758 void SWServer::Connection::resolveRegistrationReadyRequests(SWServerRegistration& registration)
760 m_registrationReadyRequests.removeAllMatching([&](auto& request) {
761 if (!registration.key().isMatching(request.topOrigin, request.clientURL))
764 registrationReady(request.identifier, registration.data());
769 } // namespace WebCore
771 #endif // ENABLE(SERVICE_WORKER)