ASSERTION FAILED: registration in WebCore::SWServerJobQueue::scriptContextStarted...
[WebKit-https.git] / Source / WebCore / workers / service / ServiceWorkerRegistration.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 "ServiceWorkerRegistration.h"
28
29 #if ENABLE(SERVICE_WORKER)
30 #include "DOMWindow.h"
31 #include "Document.h"
32 #include "Event.h"
33 #include "EventNames.h"
34 #include "Logging.h"
35 #include "ServiceWorker.h"
36 #include "ServiceWorkerContainer.h"
37 #include "ServiceWorkerTypes.h"
38 #include "WorkerGlobalScope.h"
39
40 namespace WebCore {
41
42 Ref<ServiceWorkerRegistration> ServiceWorkerRegistration::getOrCreate(ScriptExecutionContext& context, Ref<ServiceWorkerContainer>&& container, ServiceWorkerRegistrationData&& data)
43 {
44     if (auto* registration = container->registration(data.identifier)) {
45         ASSERT(!registration->m_isStopped);
46         return *registration;
47     }
48
49     return adoptRef(*new ServiceWorkerRegistration(context, WTFMove(container), WTFMove(data)));
50 }
51
52 ServiceWorkerRegistration::ServiceWorkerRegistration(ScriptExecutionContext& context, Ref<ServiceWorkerContainer>&& container, ServiceWorkerRegistrationData&& registrationData)
53     : ActiveDOMObject(&context)
54     , m_registrationData(WTFMove(registrationData))
55     , m_container(WTFMove(container))
56 {
57     LOG(ServiceWorker, "Creating registration %p for registration key %s", this, m_registrationData.key.loggingString().utf8().data());
58     suspendIfNeeded();
59
60     if (m_registrationData.installingWorker)
61         m_installingWorker = ServiceWorker::getOrCreate(context, WTFMove(*m_registrationData.installingWorker));
62     if (m_registrationData.waitingWorker)
63         m_waitingWorker = ServiceWorker::getOrCreate(context, WTFMove(*m_registrationData.waitingWorker));
64     if (m_registrationData.activeWorker)
65         m_activeWorker = ServiceWorker::getOrCreate(context, WTFMove(*m_registrationData.activeWorker));
66
67     m_container->addRegistration(*this);
68
69     relaxAdoptionRequirement();
70     updatePendingActivityForEventDispatch();
71 }
72
73 ServiceWorkerRegistration::~ServiceWorkerRegistration()
74 {
75     LOG(ServiceWorker, "Deleting registration %p for registration key %s", this, m_registrationData.key.loggingString().utf8().data());
76
77     m_container->removeRegistration(*this);
78 }
79
80 ServiceWorker* ServiceWorkerRegistration::installing()
81 {
82     return m_installingWorker.get();
83 }
84
85 ServiceWorker* ServiceWorkerRegistration::waiting()
86 {
87     return m_waitingWorker.get();
88 }
89
90 ServiceWorker* ServiceWorkerRegistration::active()
91 {
92     return m_activeWorker.get();
93 }
94
95 ServiceWorker* ServiceWorkerRegistration::getNewestWorker()
96 {
97     if (m_installingWorker)
98         return m_installingWorker.get();
99     if (m_waitingWorker)
100         return m_waitingWorker.get();
101
102     return m_activeWorker.get();
103 }
104
105 const String& ServiceWorkerRegistration::scope() const
106 {
107     return m_registrationData.scopeURL;
108 }
109
110 ServiceWorkerUpdateViaCache ServiceWorkerRegistration::updateViaCache() const
111 {
112     return m_registrationData.updateViaCache;
113 }
114
115 void ServiceWorkerRegistration::update(Ref<DeferredPromise>&& promise)
116 {
117     auto* context = scriptExecutionContext();
118     if (!context) {
119         ASSERT_NOT_REACHED();
120         promise->reject(Exception(InvalidStateError));
121         return;
122     }
123
124     auto* container = context->serviceWorkerContainer();
125     if (!container) {
126         promise->reject(Exception(InvalidStateError));
127         return;
128     }
129
130     auto* newestWorker = getNewestWorker();
131     if (!newestWorker) {
132         promise->reject(Exception(InvalidStateError, ASCIILiteral("newestWorker is null")));
133         return;
134     }
135
136     // FIXME: Support worker types.
137     container->updateRegistration(m_registrationData.scopeURL, newestWorker->scriptURL(), WorkerType::Classic, WTFMove(promise));
138 }
139
140 void ServiceWorkerRegistration::unregister(Ref<DeferredPromise>&& promise)
141 {
142     auto* context = scriptExecutionContext();
143     if (!context) {
144         ASSERT_NOT_REACHED();
145         promise->reject(Exception(InvalidStateError));
146         return;
147     }
148
149     auto* container = context->serviceWorkerContainer();
150     if (!container) {
151         promise->reject(Exception(InvalidStateError));
152         return;
153     }
154
155     container->removeRegistration(m_registrationData.scopeURL, WTFMove(promise));
156 }
157
158 void ServiceWorkerRegistration::updateStateFromServer(ServiceWorkerRegistrationState state, RefPtr<ServiceWorker>&& serviceWorker)
159 {
160     switch (state) {
161     case ServiceWorkerRegistrationState::Installing:
162         m_installingWorker = WTFMove(serviceWorker);
163         break;
164     case ServiceWorkerRegistrationState::Waiting:
165         m_waitingWorker = WTFMove(serviceWorker);
166         break;
167     case ServiceWorkerRegistrationState::Active:
168         m_activeWorker = WTFMove(serviceWorker);
169         break;
170     }
171     updatePendingActivityForEventDispatch();
172 }
173
174 void ServiceWorkerRegistration::scheduleTaskToFireUpdateFoundEvent()
175 {
176     if (m_isStopped)
177         return;
178
179     scriptExecutionContext()->postTask([this, protectedThis = makeRef(*this)](ScriptExecutionContext&) {
180         if (m_isStopped)
181             return;
182
183         ASSERT(m_pendingActivityForEventDispatch);
184         dispatchEvent(Event::create(eventNames().updatefoundEvent, false, false));
185     });
186 }
187
188 EventTargetInterface ServiceWorkerRegistration::eventTargetInterface() const
189 {
190     return ServiceWorkerRegistrationEventTargetInterfaceType;
191 }
192
193 ScriptExecutionContext* ServiceWorkerRegistration::scriptExecutionContext() const
194 {
195     return ActiveDOMObject::scriptExecutionContext();
196 }
197
198 const char* ServiceWorkerRegistration::activeDOMObjectName() const
199 {
200     return "ServiceWorkerRegistration";
201 }
202
203 bool ServiceWorkerRegistration::canSuspendForDocumentSuspension() const
204 {
205     // FIXME: We should do better as this prevents a page from entering PageCache when there is a service worker registration.
206     return !hasPendingActivity();
207 }
208
209 void ServiceWorkerRegistration::stop()
210 {
211     m_isStopped = true;
212     updatePendingActivityForEventDispatch();
213 }
214
215 void ServiceWorkerRegistration::updatePendingActivityForEventDispatch()
216 {
217     // If a registration has no ServiceWorker, then it has been cleared on server-side.
218     if (m_isStopped || !getNewestWorker()) {
219         m_pendingActivityForEventDispatch = nullptr;
220         return;
221     }
222     if (m_pendingActivityForEventDispatch)
223         return;
224     m_pendingActivityForEventDispatch = makePendingActivity(*this);
225 }
226
227 } // namespace WebCore
228
229 #endif // ENABLE(SERVICE_WORKER)