Implement "UpdateWorkerState" and use it
[WebKit-https.git] / Source / WebCore / workers / service / server / SWServerRegistration.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 "SWServerRegistration.h"
28
29 #if ENABLE(SERVICE_WORKER)
30
31 #include "SWServer.h"
32 #include "SWServerWorker.h"
33 #include "ServiceWorkerTypes.h"
34 #include "ServiceWorkerUpdateViaCache.h"
35
36 namespace WebCore {
37
38 SWServerRegistration::SWServerRegistration(SWServer& server, const ServiceWorkerRegistrationKey& key, ServiceWorkerUpdateViaCache updateViaCache, const URL& scopeURL, const URL& scriptURL)
39     : m_registrationKey(key)
40     , m_updateViaCache(updateViaCache)
41     , m_scopeURL(scopeURL)
42     , m_scriptURL(scriptURL)
43     , m_server(server)
44 {
45     m_scopeURL.removeFragmentIdentifier();
46 }
47
48 SWServerRegistration::~SWServerRegistration()
49 {
50 }
51
52 SWServerWorker* SWServerRegistration::getNewestWorker()
53 {
54     if (m_installingWorker)
55         return m_installingWorker.get();
56     if (m_waitingWorker)
57         return m_waitingWorker.get();
58
59     return m_activeWorker.get();
60 }
61
62 void SWServerRegistration::updateRegistrationState(ServiceWorkerRegistrationState state, SWServerWorker* worker)
63 {
64     LOG(ServiceWorker, "(%p) Updating registration state to %i with worker %p", this, (int)state, worker);
65     
66     switch (state) {
67     case ServiceWorkerRegistrationState::Installing:
68         m_installingWorker = worker;
69         break;
70     case ServiceWorkerRegistrationState::Waiting:
71         m_waitingWorker = worker;
72         break;
73     case ServiceWorkerRegistrationState::Active:
74         m_activeWorker = worker;
75         break;
76     };
77
78     std::optional<ServiceWorkerIdentifier> serviceWorkerIdentifier;
79     if (worker)
80         serviceWorkerIdentifier = worker->identifier();
81
82     for (auto& connectionIdentifierWithClients : m_clientRegistrationsByConnection.keys()) {
83         if (auto* connection = m_server.getConnection(connectionIdentifierWithClients))
84             connection->updateRegistrationStateInClient(m_registrationKey, state, serviceWorkerIdentifier);
85     }
86 }
87
88 void SWServerRegistration::updateWorkerState(SWServerWorker& worker, ServiceWorkerState state)
89 {
90     LOG(ServiceWorker, "Updating worker %p state to %i (%p)", &worker, (int)state, this);
91
92     worker.setState(state);
93
94     for (auto& connectionIdentifierWithClients : m_clientRegistrationsByConnection.keys()) {
95         if (auto* connection = m_server.getConnection(connectionIdentifierWithClients))
96             connection->updateWorkerStateInClient(worker.identifier(), state);
97     }
98 }
99
100 void SWServerRegistration::fireUpdateFoundEvent(uint64_t connectionIdentifier)
101 {
102     // No matter what, we send the event to the connection that scheduled the job. The client registration
103     // may not have gotten a chance to register itself yet.
104     if (auto* connection = m_server.getConnection(connectionIdentifier))
105         connection->fireUpdateFoundEvent(m_registrationKey);
106
107     for (auto& connectionIdentifierWithClients : m_clientRegistrationsByConnection.keys()) {
108         if (connectionIdentifierWithClients == connectionIdentifier)
109             continue;
110
111         if (auto* connection = m_server.getConnection(connectionIdentifierWithClients))
112             connection->fireUpdateFoundEvent(m_registrationKey);
113     }
114 }
115
116 // FIXME: This will do away once we correctly update the registration state after install.
117 void SWServerRegistration::firePostInstallEvents(uint64_t connectionIdentifier)
118 {
119     // No matter what, we send the event to the connection that scheduled the job. The client registration
120     // may not have gotten a chance to register itself yet.
121     if (auto* connection = m_server.getConnection(connectionIdentifier))
122         connection->firePostInstallEvents(m_registrationKey);
123
124     for (auto& connectionIdentifierWithClients : m_clientRegistrationsByConnection.keys()) {
125         if (auto* connection = m_server.getConnection(connectionIdentifierWithClients))
126             connection->firePostInstallEvents(m_registrationKey);
127     }
128 }
129
130 ServiceWorkerRegistrationData SWServerRegistration::data() const
131 {
132     std::optional<ServiceWorkerIdentifier> installingID;
133     if (m_installingWorker)
134         installingID = m_installingWorker->identifier();
135
136     std::optional<ServiceWorkerIdentifier> waitingID;
137     if (m_waitingWorker)
138         waitingID = m_waitingWorker->identifier();
139
140     std::optional<ServiceWorkerIdentifier> activeID;
141     if (m_activeWorker)
142         activeID = m_activeWorker->identifier();
143
144     return { m_registrationKey, identifier(), m_scopeURL, m_scriptURL, m_updateViaCache, installingID, waitingID, activeID };
145 }
146
147 void SWServerRegistration::addClientServiceWorkerRegistration(uint64_t connectionIdentifier, uint64_t clientRegistrationIdentifier)
148 {
149     auto result = m_clientRegistrationsByConnection.ensure(connectionIdentifier, [] {
150         return std::make_unique<HashSet<uint64_t>>();
151     });
152     
153     ASSERT(!result.iterator->value->contains(clientRegistrationIdentifier));
154     result.iterator->value->add(clientRegistrationIdentifier);
155 }
156
157 void SWServerRegistration::removeClientServiceWorkerRegistration(uint64_t connectionIdentifier, uint64_t clientRegistrationIdentifier)
158 {
159     auto iterator = m_clientRegistrationsByConnection.find(connectionIdentifier);
160     if (iterator == m_clientRegistrationsByConnection.end() || !iterator->value)
161         return;
162     
163     iterator->value->remove(clientRegistrationIdentifier);
164     if (iterator->value->isEmpty())
165         m_clientRegistrationsByConnection.remove(iterator);
166 }
167
168 } // namespace WebCore
169
170 #endif // ENABLE(SERVICE_WORKER)