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