Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "ServiceWorkerInfo.h"
8 :
9 : #include "ServiceWorkerScriptCache.h"
10 :
11 : BEGIN_WORKERS_NAMESPACE
12 :
13 : static_assert(nsIServiceWorkerInfo::STATE_INSTALLING == static_cast<uint16_t>(ServiceWorkerState::Installing),
14 : "ServiceWorkerState enumeration value should match state values from nsIServiceWorkerInfo.");
15 : static_assert(nsIServiceWorkerInfo::STATE_INSTALLED == static_cast<uint16_t>(ServiceWorkerState::Installed),
16 : "ServiceWorkerState enumeration value should match state values from nsIServiceWorkerInfo.");
17 : static_assert(nsIServiceWorkerInfo::STATE_ACTIVATING == static_cast<uint16_t>(ServiceWorkerState::Activating),
18 : "ServiceWorkerState enumeration value should match state values from nsIServiceWorkerInfo.");
19 : static_assert(nsIServiceWorkerInfo::STATE_ACTIVATED == static_cast<uint16_t>(ServiceWorkerState::Activated),
20 : "ServiceWorkerState enumeration value should match state values from nsIServiceWorkerInfo.");
21 : static_assert(nsIServiceWorkerInfo::STATE_REDUNDANT == static_cast<uint16_t>(ServiceWorkerState::Redundant),
22 : "ServiceWorkerState enumeration value should match state values from nsIServiceWorkerInfo.");
23 : static_assert(nsIServiceWorkerInfo::STATE_UNKNOWN == static_cast<uint16_t>(ServiceWorkerState::EndGuard_),
24 : "ServiceWorkerState enumeration value should match state values from nsIServiceWorkerInfo.");
25 :
26 0 : NS_IMPL_ISUPPORTS(ServiceWorkerInfo, nsIServiceWorkerInfo)
27 :
28 : NS_IMETHODIMP
29 0 : ServiceWorkerInfo::GetScriptSpec(nsAString& aScriptSpec)
30 : {
31 0 : AssertIsOnMainThread();
32 0 : CopyUTF8toUTF16(mScriptSpec, aScriptSpec);
33 0 : return NS_OK;
34 : }
35 :
36 : NS_IMETHODIMP
37 0 : ServiceWorkerInfo::GetCacheName(nsAString& aCacheName)
38 : {
39 0 : AssertIsOnMainThread();
40 0 : aCacheName = mCacheName;
41 0 : return NS_OK;
42 : }
43 :
44 : NS_IMETHODIMP
45 0 : ServiceWorkerInfo::GetState(uint16_t* aState)
46 : {
47 0 : MOZ_ASSERT(aState);
48 0 : AssertIsOnMainThread();
49 0 : *aState = static_cast<uint16_t>(mState);
50 0 : return NS_OK;
51 : }
52 :
53 : NS_IMETHODIMP
54 0 : ServiceWorkerInfo::GetDebugger(nsIWorkerDebugger** aResult)
55 : {
56 0 : if (NS_WARN_IF(!aResult)) {
57 0 : return NS_ERROR_FAILURE;
58 : }
59 :
60 0 : return mServiceWorkerPrivate->GetDebugger(aResult);
61 : }
62 :
63 : NS_IMETHODIMP
64 0 : ServiceWorkerInfo::GetHandlesFetchEvents(bool* aValue)
65 : {
66 0 : MOZ_ASSERT(aValue);
67 0 : AssertIsOnMainThread();
68 0 : *aValue = HandlesFetch();
69 0 : return NS_OK;
70 : }
71 :
72 : NS_IMETHODIMP
73 0 : ServiceWorkerInfo::GetInstalledTime(PRTime* _retval)
74 : {
75 0 : AssertIsOnMainThread();
76 0 : MOZ_ASSERT(_retval);
77 0 : *_retval = mInstalledTime;
78 0 : return NS_OK;
79 : }
80 :
81 : NS_IMETHODIMP
82 0 : ServiceWorkerInfo::GetActivatedTime(PRTime* _retval)
83 : {
84 0 : AssertIsOnMainThread();
85 0 : MOZ_ASSERT(_retval);
86 0 : *_retval = mActivatedTime;
87 0 : return NS_OK;
88 : }
89 :
90 : NS_IMETHODIMP
91 0 : ServiceWorkerInfo::GetRedundantTime(PRTime* _retval)
92 : {
93 0 : AssertIsOnMainThread();
94 0 : MOZ_ASSERT(_retval);
95 0 : *_retval = mRedundantTime;
96 0 : return NS_OK;
97 : }
98 :
99 : NS_IMETHODIMP
100 0 : ServiceWorkerInfo::AttachDebugger()
101 : {
102 0 : return mServiceWorkerPrivate->AttachDebugger();
103 : }
104 :
105 : NS_IMETHODIMP
106 0 : ServiceWorkerInfo::DetachDebugger()
107 : {
108 0 : return mServiceWorkerPrivate->DetachDebugger();
109 : }
110 :
111 : void
112 0 : ServiceWorkerInfo::AppendWorker(ServiceWorker* aWorker)
113 : {
114 0 : MOZ_ASSERT(aWorker);
115 : #ifdef DEBUG
116 0 : nsAutoString workerURL;
117 0 : aWorker->GetScriptURL(workerURL);
118 0 : MOZ_ASSERT(workerURL.Equals(NS_ConvertUTF8toUTF16(mScriptSpec)));
119 : #endif
120 0 : MOZ_ASSERT(!mInstances.Contains(aWorker));
121 :
122 0 : mInstances.AppendElement(aWorker);
123 0 : aWorker->SetState(State());
124 0 : }
125 :
126 : void
127 0 : ServiceWorkerInfo::RemoveWorker(ServiceWorker* aWorker)
128 : {
129 0 : MOZ_ASSERT(aWorker);
130 : #ifdef DEBUG
131 0 : nsAutoString workerURL;
132 0 : aWorker->GetScriptURL(workerURL);
133 0 : MOZ_ASSERT(workerURL.Equals(NS_ConvertUTF8toUTF16(mScriptSpec)));
134 : #endif
135 0 : MOZ_ASSERT(mInstances.Contains(aWorker));
136 :
137 0 : mInstances.RemoveElement(aWorker);
138 0 : }
139 :
140 : namespace {
141 :
142 0 : class ChangeStateUpdater final : public Runnable
143 : {
144 : public:
145 0 : ChangeStateUpdater(const nsTArray<ServiceWorker*>& aInstances,
146 : ServiceWorkerState aState)
147 0 : : Runnable("dom::workers::ChangeStateUpdater")
148 0 : , mState(aState)
149 : {
150 0 : for (size_t i = 0; i < aInstances.Length(); ++i) {
151 0 : mInstances.AppendElement(aInstances[i]);
152 : }
153 0 : }
154 :
155 0 : NS_IMETHOD Run() override
156 : {
157 : // We need to update the state of all instances atomically before notifying
158 : // them to make sure that the observed state for all instances inside
159 : // statechange event handlers is correct.
160 0 : for (size_t i = 0; i < mInstances.Length(); ++i) {
161 0 : mInstances[i]->SetState(mState);
162 : }
163 0 : for (size_t i = 0; i < mInstances.Length(); ++i) {
164 0 : mInstances[i]->DispatchStateChange(mState);
165 : }
166 :
167 0 : return NS_OK;
168 : }
169 :
170 : private:
171 : AutoTArray<RefPtr<ServiceWorker>, 1> mInstances;
172 : ServiceWorkerState mState;
173 : };
174 :
175 : }
176 :
177 : void
178 0 : ServiceWorkerInfo::UpdateState(ServiceWorkerState aState)
179 : {
180 0 : AssertIsOnMainThread();
181 : #ifdef DEBUG
182 : // Any state can directly transition to redundant, but everything else is
183 : // ordered.
184 0 : if (aState != ServiceWorkerState::Redundant) {
185 0 : MOZ_ASSERT_IF(mState == ServiceWorkerState::EndGuard_, aState == ServiceWorkerState::Installing);
186 0 : MOZ_ASSERT_IF(mState == ServiceWorkerState::Installing, aState == ServiceWorkerState::Installed);
187 0 : MOZ_ASSERT_IF(mState == ServiceWorkerState::Installed, aState == ServiceWorkerState::Activating);
188 0 : MOZ_ASSERT_IF(mState == ServiceWorkerState::Activating, aState == ServiceWorkerState::Activated);
189 : }
190 : // Activated can only go to redundant.
191 0 : MOZ_ASSERT_IF(mState == ServiceWorkerState::Activated, aState == ServiceWorkerState::Redundant);
192 : #endif
193 : // Flush any pending functional events to the worker when it transitions to the
194 : // activated state.
195 : // TODO: Do we care that these events will race with the propagation of the
196 : // state change?
197 0 : if (aState == ServiceWorkerState::Activated && mState != aState) {
198 0 : mServiceWorkerPrivate->Activated();
199 : }
200 0 : mState = aState;
201 0 : nsCOMPtr<nsIRunnable> r = new ChangeStateUpdater(mInstances, mState);
202 0 : MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r.forget()));
203 0 : if (mState == ServiceWorkerState::Redundant) {
204 0 : serviceWorkerScriptCache::PurgeCache(mPrincipal, mCacheName);
205 : }
206 0 : }
207 :
208 0 : ServiceWorkerInfo::ServiceWorkerInfo(nsIPrincipal* aPrincipal,
209 : const nsACString& aScope,
210 : const nsACString& aScriptSpec,
211 : const nsAString& aCacheName,
212 0 : nsLoadFlags aLoadFlags)
213 : : mPrincipal(aPrincipal)
214 : , mScope(aScope)
215 : , mScriptSpec(aScriptSpec)
216 : , mCacheName(aCacheName)
217 : , mLoadFlags(aLoadFlags)
218 : , mState(ServiceWorkerState::EndGuard_)
219 0 : , mServiceWorkerID(GetNextID())
220 0 : , mCreationTime(PR_Now())
221 : , mCreationTimeStamp(TimeStamp::Now())
222 : , mInstalledTime(0)
223 : , mActivatedTime(0)
224 : , mRedundantTime(0)
225 0 : , mServiceWorkerPrivate(new ServiceWorkerPrivate(this))
226 : , mSkipWaitingFlag(false)
227 0 : , mHandlesFetch(Unknown)
228 : {
229 0 : MOZ_ASSERT(mPrincipal);
230 : // cache origin attributes so we can use them off main thread
231 0 : mOriginAttributes = mPrincipal->OriginAttributesRef();
232 0 : MOZ_ASSERT(!mScope.IsEmpty());
233 0 : MOZ_ASSERT(!mScriptSpec.IsEmpty());
234 0 : MOZ_ASSERT(!mCacheName.IsEmpty());
235 0 : }
236 :
237 0 : ServiceWorkerInfo::~ServiceWorkerInfo()
238 : {
239 0 : MOZ_ASSERT(mServiceWorkerPrivate);
240 0 : mServiceWorkerPrivate->NoteDeadServiceWorkerInfo();
241 0 : }
242 :
243 : static uint64_t gServiceWorkerInfoCurrentID = 0;
244 :
245 : uint64_t
246 0 : ServiceWorkerInfo::GetNextID() const
247 : {
248 0 : return ++gServiceWorkerInfoCurrentID;
249 : }
250 :
251 : already_AddRefed<ServiceWorker>
252 0 : ServiceWorkerInfo::GetOrCreateInstance(nsPIDOMWindowInner* aWindow)
253 : {
254 0 : AssertIsOnMainThread();
255 0 : MOZ_ASSERT(aWindow);
256 :
257 0 : RefPtr<ServiceWorker> ref;
258 :
259 0 : for (uint32_t i = 0; i < mInstances.Length(); ++i) {
260 0 : MOZ_ASSERT(mInstances[i]);
261 0 : if (mInstances[i]->GetOwner() == aWindow) {
262 0 : ref = mInstances[i];
263 0 : break;
264 : }
265 : }
266 :
267 0 : if (!ref) {
268 0 : ref = new ServiceWorker(aWindow, this);
269 : }
270 :
271 0 : return ref.forget();
272 : }
273 :
274 : void
275 0 : ServiceWorkerInfo::UpdateInstalledTime()
276 : {
277 0 : MOZ_ASSERT(mState == ServiceWorkerState::Installed);
278 0 : MOZ_ASSERT(mInstalledTime == 0);
279 :
280 0 : mInstalledTime =
281 0 : mCreationTime + static_cast<PRTime>((TimeStamp::Now() -
282 0 : mCreationTimeStamp).ToMicroseconds());
283 0 : }
284 :
285 : void
286 0 : ServiceWorkerInfo::UpdateActivatedTime()
287 : {
288 0 : MOZ_ASSERT(mState == ServiceWorkerState::Activated);
289 0 : MOZ_ASSERT(mActivatedTime == 0);
290 :
291 0 : mActivatedTime =
292 0 : mCreationTime + static_cast<PRTime>((TimeStamp::Now() -
293 0 : mCreationTimeStamp).ToMicroseconds());
294 0 : }
295 :
296 : void
297 0 : ServiceWorkerInfo::UpdateRedundantTime()
298 : {
299 0 : MOZ_ASSERT(mState == ServiceWorkerState::Redundant);
300 0 : MOZ_ASSERT(mRedundantTime == 0);
301 :
302 0 : mRedundantTime =
303 0 : mCreationTime + static_cast<PRTime>((TimeStamp::Now() -
304 0 : mCreationTimeStamp).ToMicroseconds());
305 0 : }
306 :
307 : END_WORKERS_NAMESPACE
|