Unreviewed. Restabilize non-unified build.
[WebKit-https.git] / Source / WebCore / workers / service / ServiceWorkerGlobalScope.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 "ServiceWorkerGlobalScope.h"
28
29 #if ENABLE(SERVICE_WORKER)
30
31 #include "ExtendableEvent.h"
32 #include "JSDOMPromiseDeferred.h"
33 #include "SWContextManager.h"
34 #include "ServiceWorkerClient.h"
35 #include "ServiceWorkerClients.h"
36 #include "ServiceWorkerContainer.h"
37 #include "ServiceWorkerThread.h"
38 #include "ServiceWorkerWindowClient.h"
39 #include "WorkerNavigator.h"
40 #include <wtf/IsoMallocInlines.h>
41
42 namespace WebCore {
43
44 WTF_MAKE_ISO_ALLOCATED_IMPL(ServiceWorkerGlobalScope);
45
46 Ref<ServiceWorkerGlobalScope> ServiceWorkerGlobalScope::create(const ServiceWorkerContextData& data, const URL& url, Ref<SecurityOrigin>&& origin, const String& identifier, const String& userAgent, bool isOnline, ServiceWorkerThread& thread, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicy, bool shouldBypassMainWorldContentSecurityPolicy, Ref<SecurityOrigin>&& topOrigin, MonotonicTime timeOrigin, IDBClient::IDBConnectionProxy* connectionProxy, SocketProvider* socketProvider)
47 {
48     auto scope = adoptRef(*new ServiceWorkerGlobalScope { data, url, WTFMove(origin), identifier, userAgent, isOnline, thread, shouldBypassMainWorldContentSecurityPolicy, WTFMove(topOrigin), timeOrigin, connectionProxy, socketProvider });
49     scope->applyContentSecurityPolicyResponseHeaders(contentSecurityPolicy);
50     return scope;
51 }
52
53 ServiceWorkerGlobalScope::ServiceWorkerGlobalScope(const ServiceWorkerContextData& data, const URL& url, Ref<SecurityOrigin>&& origin, const String& identifier, const String& userAgent, bool isOnline, ServiceWorkerThread& thread, bool shouldBypassMainWorldContentSecurityPolicy, Ref<SecurityOrigin>&& topOrigin, MonotonicTime timeOrigin, IDBClient::IDBConnectionProxy* connectionProxy, SocketProvider* socketProvider)
54     : WorkerGlobalScope(url, WTFMove(origin), identifier, userAgent, isOnline, thread, shouldBypassMainWorldContentSecurityPolicy, WTFMove(topOrigin), timeOrigin, connectionProxy, socketProvider)
55     , m_contextData(crossThreadCopy(data))
56     , m_registration(ServiceWorkerRegistration::getOrCreate(*this, navigator().serviceWorker(), WTFMove(m_contextData.registration)))
57     , m_clients(ServiceWorkerClients::create())
58 {
59 }
60
61 ServiceWorkerGlobalScope::~ServiceWorkerGlobalScope() = default;
62
63 void ServiceWorkerGlobalScope::skipWaiting(Ref<DeferredPromise>&& promise)
64 {
65     uint64_t requestIdentifier = ++m_lastRequestIdentifier;
66     m_pendingSkipWaitingPromises.add(requestIdentifier, WTFMove(promise));
67
68     callOnMainThread([workerThread = makeRef(thread()), requestIdentifier]() mutable {
69         if (auto* connection = SWContextManager::singleton().connection()) {
70             auto identifier = workerThread->identifier();
71             connection->skipWaiting(identifier, [workerThread = WTFMove(workerThread), requestIdentifier] {
72                 workerThread->runLoop().postTask([requestIdentifier](auto& context) {
73                     auto& scope = downcast<ServiceWorkerGlobalScope>(context);
74                     if (auto promise = scope.m_pendingSkipWaitingPromises.take(requestIdentifier))
75                         promise->resolve();
76                 });
77             });
78         }
79     });
80 }
81
82 EventTargetInterface ServiceWorkerGlobalScope::eventTargetInterface() const
83 {
84     return ServiceWorkerGlobalScopeEventTargetInterfaceType;
85 }
86
87 ServiceWorkerThread& ServiceWorkerGlobalScope::thread()
88 {
89     return static_cast<ServiceWorkerThread&>(WorkerGlobalScope::thread());
90 }
91
92 ServiceWorkerClient* ServiceWorkerGlobalScope::serviceWorkerClient(ServiceWorkerClientIdentifier identifier)
93 {
94     return m_clientMap.get(identifier);
95 }
96
97 void ServiceWorkerGlobalScope::addServiceWorkerClient(ServiceWorkerClient& client)
98 {
99     auto result = m_clientMap.add(client.identifier(), &client);
100     ASSERT_UNUSED(result, result.isNewEntry);
101 }
102
103 void ServiceWorkerGlobalScope::removeServiceWorkerClient(ServiceWorkerClient& client)
104 {
105     auto isRemoved = m_clientMap.remove(client.identifier());
106     ASSERT_UNUSED(isRemoved, isRemoved);
107 }
108
109 // https://w3c.github.io/ServiceWorker/#update-service-worker-extended-events-set-algorithm
110 void ServiceWorkerGlobalScope::updateExtendedEventsSet(ExtendableEvent* newEvent)
111 {
112     ASSERT(!isMainThread());
113     ASSERT(!newEvent || !newEvent->isBeingDispatched());
114     bool hadPendingEvents = hasPendingEvents();
115     m_extendedEvents.removeAllMatching([](auto& event) {
116         return !event->pendingPromiseCount();
117     });
118
119     if (newEvent && newEvent->pendingPromiseCount()) {
120         m_extendedEvents.append(*newEvent);
121         newEvent->whenAllExtendLifetimePromisesAreSettled([this](auto&&) {
122             this->updateExtendedEventsSet();
123         });
124         // Clear out the event's target as it is the WorkerGlobalScope and we do not want to keep it
125         // alive unnecessarily.
126         newEvent->setTarget(nullptr);
127     }
128
129     bool hasPendingEvents = this->hasPendingEvents();
130     if (hasPendingEvents == hadPendingEvents)
131         return;
132
133     callOnMainThread([threadIdentifier = thread().identifier(), hasPendingEvents] {
134         if (auto* connection = SWContextManager::singleton().connection())
135             connection->setServiceWorkerHasPendingEvents(threadIdentifier, hasPendingEvents);
136     });
137 }
138
139 const ServiceWorkerContextData::ImportedScript* ServiceWorkerGlobalScope::scriptResource(const URL& url) const
140 {
141     auto iterator = m_contextData.scriptResourceMap.find(url);
142     return iterator == m_contextData.scriptResourceMap.end() ? nullptr : &iterator->value;
143 }
144
145 void ServiceWorkerGlobalScope::setScriptResource(const URL& url, ServiceWorkerContextData::ImportedScript&& script)
146 {
147     callOnMainThread([threadIdentifier = thread().identifier(), url = url.isolatedCopy(), script = script.isolatedCopy()] {
148         if (auto* connection = SWContextManager::singleton().connection())
149             connection->setScriptResource(threadIdentifier, url, script);
150     });
151
152     m_contextData.scriptResourceMap.set(url, WTFMove(script));
153 }
154
155 } // namespace WebCore
156
157 #endif // ENABLE(SERVICE_WORKER)