/src/mozilla-central/dom/workers/WorkerScope.cpp
Line | Count | Source (jump to first uncovered line) |
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 "WorkerScope.h" |
8 | | |
9 | | #include "jsapi.h" |
10 | | #include "jsfriendapi.h" |
11 | | #include "mozilla/EventListenerManager.h" |
12 | | #include "mozilla/dom/BindingDeclarations.h" |
13 | | #include "mozilla/dom/Clients.h" |
14 | | #include "mozilla/dom/ClientState.h" |
15 | | #include "mozilla/dom/Console.h" |
16 | | #include "mozilla/dom/DedicatedWorkerGlobalScopeBinding.h" |
17 | | #include "mozilla/dom/DOMPrefs.h" |
18 | | #include "mozilla/dom/Fetch.h" |
19 | | #include "mozilla/dom/FunctionBinding.h" |
20 | | #include "mozilla/dom/IDBFactory.h" |
21 | | #include "mozilla/dom/ImageBitmap.h" |
22 | | #include "mozilla/dom/ImageBitmapBinding.h" |
23 | | #include "mozilla/dom/Performance.h" |
24 | | #include "mozilla/dom/Promise.h" |
25 | | #include "mozilla/dom/PromiseWorkerProxy.h" |
26 | | #include "mozilla/dom/ServiceWorkerGlobalScopeBinding.h" |
27 | | #include "mozilla/dom/SharedWorkerGlobalScopeBinding.h" |
28 | | #include "mozilla/dom/SimpleGlobalObject.h" |
29 | | #include "mozilla/dom/WorkerDebuggerGlobalScopeBinding.h" |
30 | | #include "mozilla/dom/WorkerGlobalScopeBinding.h" |
31 | | #include "mozilla/dom/WorkerLocation.h" |
32 | | #include "mozilla/dom/WorkerNavigator.h" |
33 | | #include "mozilla/dom/cache/CacheStorage.h" |
34 | | #include "mozilla/Services.h" |
35 | | #include "mozilla/StaticPrefs.h" |
36 | | #include "nsServiceManagerUtils.h" |
37 | | |
38 | | #include "nsIDocument.h" |
39 | | #include "nsIServiceWorkerManager.h" |
40 | | #include "nsIScriptError.h" |
41 | | #include "nsIScriptTimeoutHandler.h" |
42 | | |
43 | | #ifdef ANDROID |
44 | | #include <android/log.h> |
45 | | #endif |
46 | | |
47 | | #include "Crypto.h" |
48 | | #include "Principal.h" |
49 | | #include "RuntimeService.h" |
50 | | #include "ScriptLoader.h" |
51 | | #include "WorkerPrivate.h" |
52 | | #include "WorkerRunnable.h" |
53 | | #include "mozilla/dom/ServiceWorkerManager.h" |
54 | | #include "mozilla/dom/ServiceWorkerRegistration.h" |
55 | | |
56 | | #ifdef XP_WIN |
57 | | #undef PostMessage |
58 | | #endif |
59 | | |
60 | | extern already_AddRefed<nsIScriptTimeoutHandler> |
61 | | NS_CreateJSTimeoutHandler(JSContext* aCx, |
62 | | mozilla::dom::WorkerPrivate* aWorkerPrivate, |
63 | | mozilla::dom::Function& aFunction, |
64 | | const mozilla::dom::Sequence<JS::Value>& aArguments, |
65 | | mozilla::ErrorResult& aError); |
66 | | |
67 | | extern already_AddRefed<nsIScriptTimeoutHandler> |
68 | | NS_CreateJSTimeoutHandler(JSContext* aCx, |
69 | | mozilla::dom::WorkerPrivate* aWorkerPrivate, |
70 | | const nsAString& aExpression, |
71 | | mozilla::ErrorResult& aRv); |
72 | | |
73 | | namespace mozilla { |
74 | | namespace dom { |
75 | | |
76 | | using mozilla::dom::cache::CacheStorage; |
77 | | using mozilla::ipc::PrincipalInfo; |
78 | | |
79 | | WorkerGlobalScope::WorkerGlobalScope(WorkerPrivate* aWorkerPrivate) |
80 | | : mSerialEventTarget(aWorkerPrivate->HybridEventTarget()) |
81 | | , mWindowInteractionsAllowed(0) |
82 | | , mWorkerPrivate(aWorkerPrivate) |
83 | 0 | { |
84 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
85 | 0 |
|
86 | 0 | // We should always have an event target when the global is created. |
87 | 0 | MOZ_DIAGNOSTIC_ASSERT(mSerialEventTarget); |
88 | 0 | } |
89 | | |
90 | | WorkerGlobalScope::~WorkerGlobalScope() |
91 | 0 | { |
92 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
93 | 0 | } |
94 | | |
95 | | NS_IMPL_CYCLE_COLLECTION_CLASS(WorkerGlobalScope) |
96 | | |
97 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WorkerGlobalScope, |
98 | 0 | DOMEventTargetHelper) |
99 | 0 | tmp->mWorkerPrivate->AssertIsOnWorkerThread(); |
100 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsole) |
101 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCrypto) |
102 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPerformance) |
103 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation) |
104 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigator) |
105 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexedDB) |
106 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCacheStorage) |
107 | 0 | tmp->TraverseHostObjectURIs(cb); |
108 | 0 | tmp->mWorkerPrivate->TraverseTimeouts(cb); |
109 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END |
110 | | |
111 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WorkerGlobalScope, |
112 | 0 | DOMEventTargetHelper) |
113 | 0 | tmp->mWorkerPrivate->AssertIsOnWorkerThread(); |
114 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsole) |
115 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mCrypto) |
116 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mPerformance) |
117 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation) |
118 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigator) |
119 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mIndexedDB) |
120 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mCacheStorage) |
121 | 0 | tmp->UnlinkHostObjectURIs(); |
122 | 0 | tmp->mWorkerPrivate->UnlinkTimeouts(); |
123 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_END |
124 | | |
125 | 0 | NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(WorkerGlobalScope, |
126 | 0 | DOMEventTargetHelper) |
127 | 0 | tmp->mWorkerPrivate->AssertIsOnWorkerThread(); |
128 | 0 | NS_IMPL_CYCLE_COLLECTION_TRACE_END |
129 | | |
130 | | NS_IMPL_ADDREF_INHERITED(WorkerGlobalScope, DOMEventTargetHelper) |
131 | | NS_IMPL_RELEASE_INHERITED(WorkerGlobalScope, DOMEventTargetHelper) |
132 | | |
133 | 0 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WorkerGlobalScope) |
134 | 0 | NS_INTERFACE_MAP_ENTRY(nsIGlobalObject) |
135 | 0 | NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) |
136 | 0 | NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) |
137 | | |
138 | | JSObject* |
139 | | WorkerGlobalScope::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) |
140 | 0 | { |
141 | 0 | MOZ_CRASH("We should never get here!"); |
142 | 0 | } |
143 | | |
144 | | void |
145 | | WorkerGlobalScope::NoteTerminating() |
146 | 0 | { |
147 | 0 | DisconnectEventTargetObjects(); |
148 | 0 | StartDying(); |
149 | 0 | } |
150 | | |
151 | | already_AddRefed<Console> |
152 | | WorkerGlobalScope::GetConsole(ErrorResult& aRv) |
153 | 0 | { |
154 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
155 | 0 |
|
156 | 0 | if (!mConsole) { |
157 | 0 | mConsole = Console::Create(mWorkerPrivate->GetJSContext(), |
158 | 0 | nullptr, aRv); |
159 | 0 | if (NS_WARN_IF(aRv.Failed())) { |
160 | 0 | return nullptr; |
161 | 0 | } |
162 | 0 | } |
163 | 0 | |
164 | 0 | RefPtr<Console> console = mConsole; |
165 | 0 | return console.forget(); |
166 | 0 | } |
167 | | |
168 | | Crypto* |
169 | | WorkerGlobalScope::GetCrypto(ErrorResult& aError) |
170 | 0 | { |
171 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
172 | 0 |
|
173 | 0 | if (!mCrypto) { |
174 | 0 | mCrypto = new Crypto(this); |
175 | 0 | } |
176 | 0 |
|
177 | 0 | return mCrypto; |
178 | 0 | } |
179 | | |
180 | | already_AddRefed<CacheStorage> |
181 | | WorkerGlobalScope::GetCaches(ErrorResult& aRv) |
182 | 0 | { |
183 | 0 | if (!mCacheStorage) { |
184 | 0 | MOZ_ASSERT(mWorkerPrivate); |
185 | 0 | mCacheStorage = CacheStorage::CreateOnWorker(cache::DEFAULT_NAMESPACE, this, |
186 | 0 | mWorkerPrivate, aRv); |
187 | 0 | } |
188 | 0 |
|
189 | 0 | RefPtr<CacheStorage> ref = mCacheStorage; |
190 | 0 | return ref.forget(); |
191 | 0 | } |
192 | | |
193 | | bool |
194 | | WorkerGlobalScope::IsSecureContext() const |
195 | 0 | { |
196 | 0 | bool globalSecure = |
197 | 0 | JS::GetIsSecureContext(js::GetNonCCWObjectRealm(GetWrapperPreserveColor())); |
198 | 0 | MOZ_ASSERT(globalSecure == mWorkerPrivate->IsSecureContext()); |
199 | 0 | return globalSecure; |
200 | 0 | } |
201 | | |
202 | | already_AddRefed<WorkerLocation> |
203 | | WorkerGlobalScope::Location() |
204 | 0 | { |
205 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
206 | 0 |
|
207 | 0 | if (!mLocation) { |
208 | 0 | WorkerPrivate::LocationInfo& info = mWorkerPrivate->GetLocationInfo(); |
209 | 0 |
|
210 | 0 | mLocation = WorkerLocation::Create(info); |
211 | 0 | MOZ_ASSERT(mLocation); |
212 | 0 | } |
213 | 0 |
|
214 | 0 | RefPtr<WorkerLocation> location = mLocation; |
215 | 0 | return location.forget(); |
216 | 0 | } |
217 | | |
218 | | already_AddRefed<WorkerNavigator> |
219 | | WorkerGlobalScope::Navigator() |
220 | 0 | { |
221 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
222 | 0 |
|
223 | 0 | if (!mNavigator) { |
224 | 0 | mNavigator = WorkerNavigator::Create(mWorkerPrivate->OnLine()); |
225 | 0 | MOZ_ASSERT(mNavigator); |
226 | 0 | } |
227 | 0 |
|
228 | 0 | RefPtr<WorkerNavigator> navigator = mNavigator; |
229 | 0 | return navigator.forget(); |
230 | 0 | } |
231 | | |
232 | | already_AddRefed<WorkerNavigator> |
233 | | WorkerGlobalScope::GetExistingNavigator() const |
234 | 0 | { |
235 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
236 | 0 |
|
237 | 0 | RefPtr<WorkerNavigator> navigator = mNavigator; |
238 | 0 | return navigator.forget(); |
239 | 0 | } |
240 | | |
241 | | OnErrorEventHandlerNonNull* |
242 | | WorkerGlobalScope::GetOnerror() |
243 | 0 | { |
244 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
245 | 0 |
|
246 | 0 | EventListenerManager* elm = GetExistingListenerManager(); |
247 | 0 | return elm ? elm->GetOnErrorEventHandler() : nullptr; |
248 | 0 | } |
249 | | |
250 | | void |
251 | | WorkerGlobalScope::SetOnerror(OnErrorEventHandlerNonNull* aHandler) |
252 | 0 | { |
253 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
254 | 0 |
|
255 | 0 | EventListenerManager* elm = GetOrCreateListenerManager(); |
256 | 0 | if (elm) { |
257 | 0 | elm->SetEventHandler(aHandler); |
258 | 0 | } |
259 | 0 | } |
260 | | |
261 | | void |
262 | | WorkerGlobalScope::ImportScripts(const Sequence<nsString>& aScriptURLs, |
263 | | ErrorResult& aRv) |
264 | 0 | { |
265 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
266 | 0 | workerinternals::Load(mWorkerPrivate, aScriptURLs, WorkerScript, aRv); |
267 | 0 | } |
268 | | |
269 | | int32_t |
270 | | WorkerGlobalScope::SetTimeout(JSContext* aCx, |
271 | | Function& aHandler, |
272 | | const int32_t aTimeout, |
273 | | const Sequence<JS::Value>& aArguments, |
274 | | ErrorResult& aRv) |
275 | 0 | { |
276 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
277 | 0 |
|
278 | 0 | nsCOMPtr<nsIScriptTimeoutHandler> handler = |
279 | 0 | NS_CreateJSTimeoutHandler(aCx, mWorkerPrivate, aHandler, aArguments, aRv); |
280 | 0 | if (!handler) { |
281 | 0 | return 0; |
282 | 0 | } |
283 | 0 | |
284 | 0 | return mWorkerPrivate->SetTimeout(aCx, handler, aTimeout, false, aRv); |
285 | 0 | } |
286 | | |
287 | | int32_t |
288 | | WorkerGlobalScope::SetTimeout(JSContext* aCx, |
289 | | const nsAString& aHandler, |
290 | | const int32_t aTimeout, |
291 | | const Sequence<JS::Value>& /* unused */, |
292 | | ErrorResult& aRv) |
293 | 0 | { |
294 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
295 | 0 |
|
296 | 0 | nsCOMPtr<nsIScriptTimeoutHandler> handler = |
297 | 0 | NS_CreateJSTimeoutHandler(aCx, mWorkerPrivate, aHandler, aRv); |
298 | 0 | if (!handler) { |
299 | 0 | return 0; |
300 | 0 | } |
301 | 0 | |
302 | 0 | return mWorkerPrivate->SetTimeout(aCx, handler, aTimeout, false, aRv); |
303 | 0 | } |
304 | | |
305 | | void |
306 | | WorkerGlobalScope::ClearTimeout(int32_t aHandle) |
307 | 0 | { |
308 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
309 | 0 | mWorkerPrivate->ClearTimeout(aHandle); |
310 | 0 | } |
311 | | |
312 | | int32_t |
313 | | WorkerGlobalScope::SetInterval(JSContext* aCx, |
314 | | Function& aHandler, |
315 | | const int32_t aTimeout, |
316 | | const Sequence<JS::Value>& aArguments, |
317 | | ErrorResult& aRv) |
318 | 0 | { |
319 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
320 | 0 |
|
321 | 0 | nsCOMPtr<nsIScriptTimeoutHandler> handler = |
322 | 0 | NS_CreateJSTimeoutHandler(aCx, mWorkerPrivate, aHandler, aArguments, aRv); |
323 | 0 | if (NS_WARN_IF(aRv.Failed())) { |
324 | 0 | return 0; |
325 | 0 | } |
326 | 0 | |
327 | 0 | return mWorkerPrivate->SetTimeout(aCx, handler, aTimeout, true, aRv); |
328 | 0 | } |
329 | | |
330 | | int32_t |
331 | | WorkerGlobalScope::SetInterval(JSContext* aCx, |
332 | | const nsAString& aHandler, |
333 | | const int32_t aTimeout, |
334 | | const Sequence<JS::Value>& /* unused */, |
335 | | ErrorResult& aRv) |
336 | 0 | { |
337 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
338 | 0 |
|
339 | 0 | Sequence<JS::Value> dummy; |
340 | 0 |
|
341 | 0 | nsCOMPtr<nsIScriptTimeoutHandler> handler = |
342 | 0 | NS_CreateJSTimeoutHandler(aCx, mWorkerPrivate, aHandler, aRv); |
343 | 0 | if (NS_WARN_IF(aRv.Failed())) { |
344 | 0 | return 0; |
345 | 0 | } |
346 | 0 | |
347 | 0 | return mWorkerPrivate->SetTimeout(aCx, handler, aTimeout, true, aRv); |
348 | 0 | } |
349 | | |
350 | | void |
351 | | WorkerGlobalScope::ClearInterval(int32_t aHandle) |
352 | 0 | { |
353 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
354 | 0 | mWorkerPrivate->ClearTimeout(aHandle); |
355 | 0 | } |
356 | | |
357 | | void |
358 | | WorkerGlobalScope::GetOrigin(nsAString& aOrigin) const |
359 | 0 | { |
360 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
361 | 0 | aOrigin = mWorkerPrivate->Origin(); |
362 | 0 | } |
363 | | |
364 | | void |
365 | | WorkerGlobalScope::Atob(const nsAString& aAtob, nsAString& aOutput, ErrorResult& aRv) const |
366 | 0 | { |
367 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
368 | 0 | aRv = nsContentUtils::Atob(aAtob, aOutput); |
369 | 0 | } |
370 | | |
371 | | void |
372 | | WorkerGlobalScope::Btoa(const nsAString& aBtoa, nsAString& aOutput, ErrorResult& aRv) const |
373 | 0 | { |
374 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
375 | 0 | aRv = nsContentUtils::Btoa(aBtoa, aOutput); |
376 | 0 | } |
377 | | |
378 | | void |
379 | | WorkerGlobalScope::Dump(const Optional<nsAString>& aString) const |
380 | 0 | { |
381 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
382 | 0 |
|
383 | 0 | if (!aString.WasPassed()) { |
384 | 0 | return; |
385 | 0 | } |
386 | 0 | |
387 | 0 | #if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP)) |
388 | 0 | if (!DOMPrefs::DumpEnabled()) { |
389 | 0 | return; |
390 | 0 | } |
391 | 0 | #endif |
392 | 0 | |
393 | 0 | NS_ConvertUTF16toUTF8 str(aString.Value()); |
394 | 0 |
|
395 | 0 | MOZ_LOG(nsContentUtils::DOMDumpLog(), LogLevel::Debug, ("[Worker.Dump] %s", str.get())); |
396 | | #ifdef ANDROID |
397 | | __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", str.get()); |
398 | | #endif |
399 | | fputs(str.get(), stdout); |
400 | 0 | fflush(stdout); |
401 | 0 | } |
402 | | |
403 | | Performance* |
404 | | WorkerGlobalScope::GetPerformance() |
405 | 0 | { |
406 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
407 | 0 |
|
408 | 0 | if (!mPerformance) { |
409 | 0 | mPerformance = Performance::CreateForWorker(mWorkerPrivate); |
410 | 0 | } |
411 | 0 |
|
412 | 0 | return mPerformance; |
413 | 0 | } |
414 | | |
415 | | bool |
416 | | WorkerGlobalScope::IsInAutomation(JSContext* aCx, JSObject* /* unused */) |
417 | 0 | { |
418 | 0 | return GetWorkerPrivateFromContext(aCx)->IsInAutomation(); |
419 | 0 | } |
420 | | |
421 | | void |
422 | | WorkerGlobalScope::GetJSTestingFunctions(JSContext* aCx, |
423 | | JS::MutableHandle<JSObject*> aFunctions, |
424 | | ErrorResult& aRv) |
425 | 0 | { |
426 | 0 | JSObject* obj = js::GetTestingFunctions(aCx); |
427 | 0 | if (!obj) { |
428 | 0 | aRv.Throw(NS_ERROR_OUT_OF_MEMORY); |
429 | 0 | return; |
430 | 0 | } |
431 | 0 | |
432 | 0 | aFunctions.set(obj); |
433 | 0 | } |
434 | | |
435 | | already_AddRefed<Promise> |
436 | | WorkerGlobalScope::Fetch(const RequestOrUSVString& aInput, |
437 | | const RequestInit& aInit, |
438 | | CallerType aCallerType, ErrorResult& aRv) |
439 | 0 | { |
440 | 0 | return FetchRequest(this, aInput, aInit, aCallerType, aRv); |
441 | 0 | } |
442 | | |
443 | | already_AddRefed<IDBFactory> |
444 | | WorkerGlobalScope::GetIndexedDB(ErrorResult& aErrorResult) |
445 | 0 | { |
446 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
447 | 0 |
|
448 | 0 | RefPtr<IDBFactory> indexedDB = mIndexedDB; |
449 | 0 |
|
450 | 0 | if (!indexedDB) { |
451 | 0 | if (!mWorkerPrivate->IsStorageAllowed()) { |
452 | 0 | NS_WARNING("IndexedDB is not allowed in this worker!"); |
453 | 0 | aErrorResult = NS_ERROR_DOM_SECURITY_ERR; |
454 | 0 | return nullptr; |
455 | 0 | } |
456 | 0 |
|
457 | 0 | JSContext* cx = mWorkerPrivate->GetJSContext(); |
458 | 0 | MOZ_ASSERT(cx); |
459 | 0 |
|
460 | 0 | JS::Rooted<JSObject*> owningObject(cx, GetGlobalJSObject()); |
461 | 0 | MOZ_ASSERT(owningObject); |
462 | 0 |
|
463 | 0 | const PrincipalInfo& principalInfo = mWorkerPrivate->GetPrincipalInfo(); |
464 | 0 |
|
465 | 0 | nsresult rv = |
466 | 0 | IDBFactory::CreateForWorker(cx, |
467 | 0 | owningObject, |
468 | 0 | principalInfo, |
469 | 0 | mWorkerPrivate->WindowID(), |
470 | 0 | getter_AddRefs(indexedDB)); |
471 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
472 | 0 | aErrorResult = rv; |
473 | 0 | return nullptr; |
474 | 0 | } |
475 | 0 | |
476 | 0 | mIndexedDB = indexedDB; |
477 | 0 | } |
478 | 0 |
|
479 | 0 | return indexedDB.forget(); |
480 | 0 | } |
481 | | |
482 | | already_AddRefed<Promise> |
483 | | WorkerGlobalScope::CreateImageBitmap(JSContext* aCx, |
484 | | const ImageBitmapSource& aImage, |
485 | | ErrorResult& aRv) |
486 | 0 | { |
487 | 0 | if (aImage.IsArrayBuffer() || aImage.IsArrayBufferView()) { |
488 | 0 | aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); |
489 | 0 | return nullptr; |
490 | 0 | } |
491 | 0 | |
492 | 0 | return ImageBitmap::Create(this, aImage, Nothing(), aRv); |
493 | 0 | } |
494 | | |
495 | | already_AddRefed<Promise> |
496 | | WorkerGlobalScope::CreateImageBitmap(JSContext* aCx, |
497 | | const ImageBitmapSource& aImage, |
498 | | int32_t aSx, int32_t aSy, int32_t aSw, int32_t aSh, |
499 | | ErrorResult& aRv) |
500 | 0 | { |
501 | 0 | if (aImage.IsArrayBuffer() || aImage.IsArrayBufferView()) { |
502 | 0 | aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); |
503 | 0 | return nullptr; |
504 | 0 | } |
505 | 0 | |
506 | 0 | return ImageBitmap::Create(this, aImage, Some(gfx::IntRect(aSx, aSy, aSw, aSh)), aRv); |
507 | 0 | } |
508 | | |
509 | | already_AddRefed<mozilla::dom::Promise> |
510 | | WorkerGlobalScope::CreateImageBitmap(JSContext* aCx, |
511 | | const ImageBitmapSource& aImage, |
512 | | int32_t aOffset, int32_t aLength, |
513 | | ImageBitmapFormat aFormat, |
514 | | const Sequence<ChannelPixelLayout>& aLayout, |
515 | | ErrorResult& aRv) |
516 | 0 | { |
517 | 0 | if (!StaticPrefs::canvas_imagebitmap_extensions_enabled()) { |
518 | 0 | aRv.Throw(NS_ERROR_TYPE_ERR); |
519 | 0 | return nullptr; |
520 | 0 | } |
521 | 0 | |
522 | 0 | if (aImage.IsArrayBuffer() || aImage.IsArrayBufferView()) { |
523 | 0 | return ImageBitmap::Create(this, aImage, aOffset, aLength, aFormat, aLayout, |
524 | 0 | aRv); |
525 | 0 | } else { |
526 | 0 | aRv.Throw(NS_ERROR_TYPE_ERR); |
527 | 0 | return nullptr; |
528 | 0 | } |
529 | 0 | } |
530 | | |
531 | | nsresult |
532 | | WorkerGlobalScope::Dispatch(TaskCategory aCategory, |
533 | | already_AddRefed<nsIRunnable>&& aRunnable) |
534 | 0 | { |
535 | 0 | return EventTargetFor(aCategory)->Dispatch(std::move(aRunnable), |
536 | 0 | NS_DISPATCH_NORMAL); |
537 | 0 | } |
538 | | |
539 | | nsISerialEventTarget* |
540 | | WorkerGlobalScope::EventTargetFor(TaskCategory aCategory) const |
541 | 0 | { |
542 | 0 | return mSerialEventTarget; |
543 | 0 | } |
544 | | |
545 | | AbstractThread* |
546 | | WorkerGlobalScope::AbstractMainThreadFor(TaskCategory aCategory) |
547 | 0 | { |
548 | 0 | MOZ_CRASH("AbstractMainThreadFor not supported for workers."); |
549 | 0 | } |
550 | | |
551 | | Maybe<ClientInfo> |
552 | | WorkerGlobalScope::GetClientInfo() const |
553 | 0 | { |
554 | 0 | return mWorkerPrivate->GetClientInfo(); |
555 | 0 | } |
556 | | |
557 | | Maybe<ClientState> |
558 | | WorkerGlobalScope::GetClientState() const |
559 | 0 | { |
560 | 0 | Maybe<ClientState> state; |
561 | 0 | state.emplace(mWorkerPrivate->GetClientState()); |
562 | 0 | return state; |
563 | 0 | } |
564 | | |
565 | | Maybe<ServiceWorkerDescriptor> |
566 | | WorkerGlobalScope::GetController() const |
567 | 0 | { |
568 | 0 | return mWorkerPrivate->GetController(); |
569 | 0 | } |
570 | | |
571 | | RefPtr<mozilla::dom::ServiceWorkerRegistration> |
572 | | WorkerGlobalScope::GetServiceWorkerRegistration(const ServiceWorkerRegistrationDescriptor& aDescriptor) const |
573 | 0 | { |
574 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
575 | 0 | RefPtr<ServiceWorkerRegistration> ref; |
576 | 0 | ForEachEventTargetObject([&] (DOMEventTargetHelper* aTarget, bool* aDoneOut) { |
577 | 0 | RefPtr<ServiceWorkerRegistration> swr = do_QueryObject(aTarget); |
578 | 0 | if (!swr || !swr->MatchesDescriptor(aDescriptor)) { |
579 | 0 | return; |
580 | 0 | } |
581 | 0 | |
582 | 0 | ref = swr.forget(); |
583 | 0 | *aDoneOut = true; |
584 | 0 | }); |
585 | 0 | return ref.forget(); |
586 | 0 | } |
587 | | |
588 | | RefPtr<ServiceWorkerRegistration> |
589 | | WorkerGlobalScope::GetOrCreateServiceWorkerRegistration(const ServiceWorkerRegistrationDescriptor& aDescriptor) |
590 | 0 | { |
591 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
592 | 0 | RefPtr<ServiceWorkerRegistration> ref = GetServiceWorkerRegistration(aDescriptor); |
593 | 0 | if (!ref) { |
594 | 0 | ref = ServiceWorkerRegistration::CreateForWorker(mWorkerPrivate, this, |
595 | 0 | aDescriptor); |
596 | 0 | } |
597 | 0 | return ref.forget(); |
598 | 0 | } |
599 | | |
600 | | DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate, |
601 | | const nsString& aName) |
602 | | : WorkerGlobalScope(aWorkerPrivate) |
603 | | , mName(aName) |
604 | 0 | { |
605 | 0 | } |
606 | | |
607 | | bool |
608 | | DedicatedWorkerGlobalScope::WrapGlobalObject(JSContext* aCx, |
609 | | JS::MutableHandle<JSObject*> aReflector) |
610 | 0 | { |
611 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
612 | 0 | MOZ_ASSERT(!mWorkerPrivate->IsSharedWorker()); |
613 | 0 |
|
614 | 0 | JS::RealmOptions options; |
615 | 0 | mWorkerPrivate->CopyJSRealmOptions(options); |
616 | 0 |
|
617 | 0 | const bool usesSystemPrincipal = mWorkerPrivate->UsesSystemPrincipal(); |
618 | 0 |
|
619 | 0 | // Note that xpc::ShouldDiscardSystemSource() and |
620 | 0 | // xpc::ExtraWarningsForSystemJS() read prefs that are cached on the main |
621 | 0 | // thread. This is benignly racey. |
622 | 0 | const bool discardSource = usesSystemPrincipal && |
623 | 0 | xpc::ShouldDiscardSystemSource(); |
624 | 0 | const bool extraWarnings = usesSystemPrincipal && |
625 | 0 | xpc::ExtraWarningsForSystemJS(); |
626 | 0 |
|
627 | 0 | JS::RealmBehaviors& behaviors = options.behaviors(); |
628 | 0 | behaviors.setDiscardSource(discardSource) |
629 | 0 | .extraWarningsOverride().set(extraWarnings); |
630 | 0 |
|
631 | 0 | const bool sharedMemoryEnabled = xpc::SharedMemoryEnabled(); |
632 | 0 |
|
633 | 0 | JS::RealmCreationOptions& creationOptions = options.creationOptions(); |
634 | 0 | creationOptions.setSharedMemoryAndAtomicsEnabled(sharedMemoryEnabled); |
635 | 0 |
|
636 | 0 | return DedicatedWorkerGlobalScope_Binding::Wrap(aCx, this, this, |
637 | 0 | options, |
638 | 0 | GetWorkerPrincipal(), |
639 | 0 | true, aReflector); |
640 | 0 | } |
641 | | |
642 | | void |
643 | | DedicatedWorkerGlobalScope::PostMessage(JSContext* aCx, |
644 | | JS::Handle<JS::Value> aMessage, |
645 | | const Sequence<JSObject*>& aTransferable, |
646 | | ErrorResult& aRv) |
647 | 0 | { |
648 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
649 | 0 | mWorkerPrivate->PostMessageToParent(aCx, aMessage, aTransferable, aRv); |
650 | 0 | } |
651 | | |
652 | | void |
653 | | DedicatedWorkerGlobalScope::Close() |
654 | 0 | { |
655 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
656 | 0 | mWorkerPrivate->CloseInternal(); |
657 | 0 | } |
658 | | |
659 | | SharedWorkerGlobalScope::SharedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate, |
660 | | const nsString& aName) |
661 | | : WorkerGlobalScope(aWorkerPrivate), mName(aName) |
662 | 0 | { |
663 | 0 | } |
664 | | |
665 | | bool |
666 | | SharedWorkerGlobalScope::WrapGlobalObject(JSContext* aCx, |
667 | | JS::MutableHandle<JSObject*> aReflector) |
668 | 0 | { |
669 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
670 | 0 | MOZ_ASSERT(mWorkerPrivate->IsSharedWorker()); |
671 | 0 |
|
672 | 0 | JS::RealmOptions options; |
673 | 0 | mWorkerPrivate->CopyJSRealmOptions(options); |
674 | 0 |
|
675 | 0 | return SharedWorkerGlobalScope_Binding::Wrap(aCx, this, this, options, |
676 | 0 | GetWorkerPrincipal(), |
677 | 0 | true, aReflector); |
678 | 0 | } |
679 | | |
680 | | void |
681 | | SharedWorkerGlobalScope::Close() |
682 | 0 | { |
683 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
684 | 0 | mWorkerPrivate->CloseInternal(); |
685 | 0 | } |
686 | | |
687 | | NS_IMPL_CYCLE_COLLECTION_INHERITED(ServiceWorkerGlobalScope, WorkerGlobalScope, |
688 | | mClients, mRegistration) |
689 | 0 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ServiceWorkerGlobalScope) |
690 | 0 | NS_INTERFACE_MAP_END_INHERITING(WorkerGlobalScope) |
691 | | |
692 | | NS_IMPL_ADDREF_INHERITED(ServiceWorkerGlobalScope, WorkerGlobalScope) |
693 | | NS_IMPL_RELEASE_INHERITED(ServiceWorkerGlobalScope, WorkerGlobalScope) |
694 | | |
695 | | ServiceWorkerGlobalScope::ServiceWorkerGlobalScope(WorkerPrivate* aWorkerPrivate, |
696 | | const ServiceWorkerRegistrationDescriptor& aRegistrationDescriptor) |
697 | | : WorkerGlobalScope(aWorkerPrivate) |
698 | | , mScope(NS_ConvertUTF8toUTF16(aRegistrationDescriptor.Scope())) |
699 | | |
700 | | // Eagerly create the registration because we will need to receive updates |
701 | | // about the state of the registration. We can't wait until first access |
702 | | // to start receiving these. |
703 | | , mRegistration(GetOrCreateServiceWorkerRegistration(aRegistrationDescriptor)) |
704 | 0 | { |
705 | 0 | } |
706 | | |
707 | | ServiceWorkerGlobalScope::~ServiceWorkerGlobalScope() |
708 | 0 | { |
709 | 0 | } |
710 | | |
711 | | bool |
712 | | ServiceWorkerGlobalScope::WrapGlobalObject(JSContext* aCx, |
713 | | JS::MutableHandle<JSObject*> aReflector) |
714 | 0 | { |
715 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
716 | 0 | MOZ_ASSERT(mWorkerPrivate->IsServiceWorker()); |
717 | 0 |
|
718 | 0 | JS::RealmOptions options; |
719 | 0 | mWorkerPrivate->CopyJSRealmOptions(options); |
720 | 0 |
|
721 | 0 | return ServiceWorkerGlobalScope_Binding::Wrap(aCx, this, this, options, |
722 | 0 | GetWorkerPrincipal(), |
723 | 0 | true, aReflector); |
724 | 0 | } |
725 | | |
726 | | already_AddRefed<Clients> |
727 | | ServiceWorkerGlobalScope::GetClients() |
728 | 0 | { |
729 | 0 | if (!mClients) { |
730 | 0 | mClients = new Clients(this); |
731 | 0 | } |
732 | 0 |
|
733 | 0 | RefPtr<Clients> ref = mClients; |
734 | 0 | return ref.forget(); |
735 | 0 | } |
736 | | |
737 | | ServiceWorkerRegistration* |
738 | | ServiceWorkerGlobalScope::Registration() |
739 | 0 | { |
740 | 0 | return mRegistration; |
741 | 0 | } |
742 | | |
743 | | EventHandlerNonNull* |
744 | | ServiceWorkerGlobalScope::GetOnfetch() |
745 | 0 | { |
746 | 0 | MOZ_ASSERT(mWorkerPrivate); |
747 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
748 | 0 |
|
749 | 0 | return GetEventHandler(nsGkAtoms::onfetch); |
750 | 0 | } |
751 | | |
752 | | namespace { |
753 | | |
754 | | class ReportFetchListenerWarningRunnable final : public Runnable |
755 | | { |
756 | | const nsCString mScope; |
757 | | nsCString mSourceSpec; |
758 | | uint32_t mLine; |
759 | | uint32_t mColumn; |
760 | | |
761 | | public: |
762 | | explicit ReportFetchListenerWarningRunnable(const nsString& aScope) |
763 | | : mozilla::Runnable("ReportFetchListenerWarningRunnable") |
764 | | , mScope(NS_ConvertUTF16toUTF8(aScope)) |
765 | 0 | { |
766 | 0 | WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); |
767 | 0 | MOZ_ASSERT(workerPrivate); |
768 | 0 | JSContext* cx = workerPrivate->GetJSContext(); |
769 | 0 | MOZ_ASSERT(cx); |
770 | 0 |
|
771 | 0 | nsJSUtils::GetCallingLocation(cx, mSourceSpec, &mLine, &mColumn); |
772 | 0 | } |
773 | | |
774 | | NS_IMETHOD |
775 | | Run() override |
776 | 0 | { |
777 | 0 | AssertIsOnMainThread(); |
778 | 0 |
|
779 | 0 | ServiceWorkerManager::LocalizeAndReportToAllClients(mScope, "ServiceWorkerNoFetchHandler", |
780 | 0 | nsTArray<nsString>{}, nsIScriptError::warningFlag, NS_ConvertUTF8toUTF16(mSourceSpec), |
781 | 0 | EmptyString(), mLine, mColumn); |
782 | 0 |
|
783 | 0 | return NS_OK; |
784 | 0 | } |
785 | | }; |
786 | | |
787 | | } // anonymous namespace |
788 | | |
789 | | void |
790 | | ServiceWorkerGlobalScope::SetOnfetch(mozilla::dom::EventHandlerNonNull* aCallback) |
791 | 0 | { |
792 | 0 | MOZ_ASSERT(mWorkerPrivate); |
793 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
794 | 0 |
|
795 | 0 | if (aCallback) { |
796 | 0 | if (mWorkerPrivate->WorkerScriptExecutedSuccessfully()) { |
797 | 0 | RefPtr<Runnable> r = new ReportFetchListenerWarningRunnable(mScope); |
798 | 0 | mWorkerPrivate->DispatchToMainThread(r.forget()); |
799 | 0 | } |
800 | 0 | mWorkerPrivate->SetFetchHandlerWasAdded(); |
801 | 0 | } |
802 | 0 | SetEventHandler(nsGkAtoms::onfetch, aCallback); |
803 | 0 | } |
804 | | |
805 | | void |
806 | | ServiceWorkerGlobalScope::EventListenerAdded(nsAtom* aType) |
807 | 0 | { |
808 | 0 | MOZ_ASSERT(mWorkerPrivate); |
809 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
810 | 0 |
|
811 | 0 | if (aType != nsGkAtoms::onfetch) { |
812 | 0 | return; |
813 | 0 | } |
814 | 0 | |
815 | 0 | if (mWorkerPrivate->WorkerScriptExecutedSuccessfully()) { |
816 | 0 | RefPtr<Runnable> r = new ReportFetchListenerWarningRunnable(mScope); |
817 | 0 | mWorkerPrivate->DispatchToMainThread(r.forget()); |
818 | 0 | } |
819 | 0 |
|
820 | 0 | mWorkerPrivate->SetFetchHandlerWasAdded(); |
821 | 0 | } |
822 | | |
823 | | namespace { |
824 | | |
825 | | class SkipWaitingResultRunnable final : public WorkerRunnable |
826 | | { |
827 | | RefPtr<PromiseWorkerProxy> mPromiseProxy; |
828 | | |
829 | | public: |
830 | | SkipWaitingResultRunnable(WorkerPrivate* aWorkerPrivate, |
831 | | PromiseWorkerProxy* aPromiseProxy) |
832 | | : WorkerRunnable(aWorkerPrivate) |
833 | | , mPromiseProxy(aPromiseProxy) |
834 | 0 | { |
835 | 0 | AssertIsOnMainThread(); |
836 | 0 | } |
837 | | |
838 | | virtual bool |
839 | | WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override |
840 | 0 | { |
841 | 0 | MOZ_ASSERT(aWorkerPrivate); |
842 | 0 | aWorkerPrivate->AssertIsOnWorkerThread(); |
843 | 0 |
|
844 | 0 | RefPtr<Promise> promise = mPromiseProxy->WorkerPromise(); |
845 | 0 | promise->MaybeResolveWithUndefined(); |
846 | 0 |
|
847 | 0 | // Release the reference on the worker thread. |
848 | 0 | mPromiseProxy->CleanUp(); |
849 | 0 |
|
850 | 0 | return true; |
851 | 0 | } |
852 | | }; |
853 | | |
854 | | class WorkerScopeSkipWaitingRunnable final : public Runnable |
855 | | { |
856 | | RefPtr<PromiseWorkerProxy> mPromiseProxy; |
857 | | nsCString mScope; |
858 | | |
859 | | public: |
860 | | WorkerScopeSkipWaitingRunnable(PromiseWorkerProxy* aPromiseProxy, |
861 | | const nsCString& aScope) |
862 | | : mozilla::Runnable("WorkerScopeSkipWaitingRunnable") |
863 | | , mPromiseProxy(aPromiseProxy) |
864 | | , mScope(aScope) |
865 | 0 | { |
866 | 0 | MOZ_ASSERT(aPromiseProxy); |
867 | 0 | } |
868 | | |
869 | | NS_IMETHOD |
870 | | Run() override |
871 | 0 | { |
872 | 0 | AssertIsOnMainThread(); |
873 | 0 |
|
874 | 0 | MutexAutoLock lock(mPromiseProxy->Lock()); |
875 | 0 | if (mPromiseProxy->CleanedUp()) { |
876 | 0 | return NS_OK; |
877 | 0 | } |
878 | 0 | |
879 | 0 | WorkerPrivate* workerPrivate = mPromiseProxy->GetWorkerPrivate(); |
880 | 0 | MOZ_DIAGNOSTIC_ASSERT(workerPrivate); |
881 | 0 |
|
882 | 0 | RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); |
883 | 0 | if (swm) { |
884 | 0 | swm->SetSkipWaitingFlag(workerPrivate->GetPrincipal(), mScope, |
885 | 0 | workerPrivate->ServiceWorkerID()); |
886 | 0 | } |
887 | 0 |
|
888 | 0 | RefPtr<SkipWaitingResultRunnable> runnable = |
889 | 0 | new SkipWaitingResultRunnable(workerPrivate, mPromiseProxy); |
890 | 0 |
|
891 | 0 | if (!runnable->Dispatch()) { |
892 | 0 | NS_WARNING("Failed to dispatch SkipWaitingResultRunnable to the worker."); |
893 | 0 | } |
894 | 0 | return NS_OK; |
895 | 0 | } |
896 | | }; |
897 | | |
898 | | } // namespace |
899 | | |
900 | | already_AddRefed<Promise> |
901 | | ServiceWorkerGlobalScope::SkipWaiting(ErrorResult& aRv) |
902 | 0 | { |
903 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
904 | 0 | MOZ_ASSERT(mWorkerPrivate->IsServiceWorker()); |
905 | 0 |
|
906 | 0 | RefPtr<Promise> promise = Promise::Create(this, aRv); |
907 | 0 | if (NS_WARN_IF(aRv.Failed())) { |
908 | 0 | return nullptr; |
909 | 0 | } |
910 | 0 | |
911 | 0 | RefPtr<PromiseWorkerProxy> promiseProxy = |
912 | 0 | PromiseWorkerProxy::Create(mWorkerPrivate, promise); |
913 | 0 | if (!promiseProxy) { |
914 | 0 | promise->MaybeResolveWithUndefined(); |
915 | 0 | return promise.forget(); |
916 | 0 | } |
917 | 0 | |
918 | 0 | RefPtr<WorkerScopeSkipWaitingRunnable> runnable = |
919 | 0 | new WorkerScopeSkipWaitingRunnable(promiseProxy, |
920 | 0 | NS_ConvertUTF16toUTF8(mScope)); |
921 | 0 |
|
922 | 0 | MOZ_ALWAYS_SUCCEEDS(mWorkerPrivate->DispatchToMainThread(runnable.forget())); |
923 | 0 | return promise.forget(); |
924 | 0 | } |
925 | | |
926 | | WorkerDebuggerGlobalScope::WorkerDebuggerGlobalScope( |
927 | | WorkerPrivate* aWorkerPrivate) |
928 | | : mWorkerPrivate(aWorkerPrivate) |
929 | | , mSerialEventTarget(aWorkerPrivate->HybridEventTarget()) |
930 | 0 | { |
931 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
932 | 0 |
|
933 | 0 | // We should always have an event target when the global is created. |
934 | 0 | MOZ_DIAGNOSTIC_ASSERT(mSerialEventTarget); |
935 | 0 | } |
936 | | |
937 | | WorkerDebuggerGlobalScope::~WorkerDebuggerGlobalScope() |
938 | 0 | { |
939 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
940 | 0 | } |
941 | | |
942 | | NS_IMPL_CYCLE_COLLECTION_CLASS(WorkerDebuggerGlobalScope) |
943 | | |
944 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WorkerDebuggerGlobalScope, |
945 | 0 | DOMEventTargetHelper) |
946 | 0 | tmp->mWorkerPrivate->AssertIsOnWorkerThread(); |
947 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsole) |
948 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END |
949 | | |
950 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WorkerDebuggerGlobalScope, |
951 | 0 | DOMEventTargetHelper) |
952 | 0 | tmp->mWorkerPrivate->AssertIsOnWorkerThread(); |
953 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsole) |
954 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_END |
955 | | |
956 | 0 | NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(WorkerDebuggerGlobalScope, |
957 | 0 | DOMEventTargetHelper) |
958 | 0 | tmp->mWorkerPrivate->AssertIsOnWorkerThread(); |
959 | 0 | NS_IMPL_CYCLE_COLLECTION_TRACE_END |
960 | | |
961 | | NS_IMPL_ADDREF_INHERITED(WorkerDebuggerGlobalScope, DOMEventTargetHelper) |
962 | | NS_IMPL_RELEASE_INHERITED(WorkerDebuggerGlobalScope, DOMEventTargetHelper) |
963 | | |
964 | 0 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WorkerDebuggerGlobalScope) |
965 | 0 | NS_INTERFACE_MAP_ENTRY(nsIGlobalObject) |
966 | 0 | NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) |
967 | | |
968 | | bool |
969 | | WorkerDebuggerGlobalScope::WrapGlobalObject(JSContext* aCx, |
970 | | JS::MutableHandle<JSObject*> aReflector) |
971 | 0 | { |
972 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
973 | 0 |
|
974 | 0 | JS::RealmOptions options; |
975 | 0 | mWorkerPrivate->CopyJSRealmOptions(options); |
976 | 0 |
|
977 | 0 | return WorkerDebuggerGlobalScope_Binding::Wrap(aCx, this, this, options, |
978 | 0 | GetWorkerPrincipal(), true, |
979 | 0 | aReflector); |
980 | 0 | } |
981 | | |
982 | | void |
983 | | WorkerDebuggerGlobalScope::GetGlobal(JSContext* aCx, |
984 | | JS::MutableHandle<JSObject*> aGlobal, |
985 | | ErrorResult& aRv) |
986 | 0 | { |
987 | 0 | WorkerGlobalScope* scope = mWorkerPrivate->GetOrCreateGlobalScope(aCx); |
988 | 0 | if (!scope) { |
989 | 0 | aRv.Throw(NS_ERROR_FAILURE); |
990 | 0 | return; |
991 | 0 | } |
992 | 0 | |
993 | 0 | aGlobal.set(scope->GetWrapper()); |
994 | 0 | } |
995 | | |
996 | | void |
997 | | WorkerDebuggerGlobalScope::CreateSandbox(JSContext* aCx, const nsAString& aName, |
998 | | JS::Handle<JSObject*> aPrototype, |
999 | | JS::MutableHandle<JSObject*> aResult, |
1000 | | ErrorResult& aRv) |
1001 | 0 | { |
1002 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
1003 | 0 |
|
1004 | 0 | aResult.set(nullptr); |
1005 | 0 |
|
1006 | 0 | JS::Rooted<JS::Value> protoVal(aCx); |
1007 | 0 | protoVal.setObjectOrNull(aPrototype); |
1008 | 0 | JS::Rooted<JSObject*> sandbox(aCx, |
1009 | 0 | SimpleGlobalObject::Create(SimpleGlobalObject::GlobalType::WorkerDebuggerSandbox, |
1010 | 0 | protoVal)); |
1011 | 0 |
|
1012 | 0 | if (!sandbox) { |
1013 | 0 | aRv.Throw(NS_ERROR_OUT_OF_MEMORY); |
1014 | 0 | return; |
1015 | 0 | } |
1016 | 0 | |
1017 | 0 | if (!JS_WrapObject(aCx, &sandbox)) { |
1018 | 0 | aRv.NoteJSContextException(aCx); |
1019 | 0 | return; |
1020 | 0 | } |
1021 | 0 | |
1022 | 0 | aResult.set(sandbox); |
1023 | 0 | } |
1024 | | |
1025 | | void |
1026 | | WorkerDebuggerGlobalScope::LoadSubScript(JSContext* aCx, |
1027 | | const nsAString& aURL, |
1028 | | const Optional<JS::Handle<JSObject*>>& aSandbox, |
1029 | | ErrorResult& aRv) |
1030 | 0 | { |
1031 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
1032 | 0 |
|
1033 | 0 | Maybe<JSAutoRealm> ar; |
1034 | 0 | if (aSandbox.WasPassed()) { |
1035 | 0 | JS::Rooted<JSObject*> sandbox(aCx, js::CheckedUnwrap(aSandbox.Value())); |
1036 | 0 | if (!IsWorkerDebuggerSandbox(sandbox)) { |
1037 | 0 | aRv.Throw(NS_ERROR_INVALID_ARG); |
1038 | 0 | return; |
1039 | 0 | } |
1040 | 0 | |
1041 | 0 | ar.emplace(aCx, sandbox); |
1042 | 0 | } |
1043 | 0 |
|
1044 | 0 | nsTArray<nsString> urls; |
1045 | 0 | urls.AppendElement(aURL); |
1046 | 0 | workerinternals::Load(mWorkerPrivate, urls, DebuggerScript, aRv); |
1047 | 0 | } |
1048 | | |
1049 | | void |
1050 | | WorkerDebuggerGlobalScope::EnterEventLoop() |
1051 | 0 | { |
1052 | 0 | mWorkerPrivate->EnterDebuggerEventLoop(); |
1053 | 0 | } |
1054 | | |
1055 | | void |
1056 | | WorkerDebuggerGlobalScope::LeaveEventLoop() |
1057 | 0 | { |
1058 | 0 | mWorkerPrivate->LeaveDebuggerEventLoop(); |
1059 | 0 | } |
1060 | | |
1061 | | void |
1062 | | WorkerDebuggerGlobalScope::PostMessage(const nsAString& aMessage) |
1063 | 0 | { |
1064 | 0 | mWorkerPrivate->PostMessageToDebugger(aMessage); |
1065 | 0 | } |
1066 | | |
1067 | | void |
1068 | | WorkerDebuggerGlobalScope::SetImmediate(Function& aHandler, ErrorResult& aRv) |
1069 | 0 | { |
1070 | 0 | mWorkerPrivate->SetDebuggerImmediate(aHandler, aRv); |
1071 | 0 | } |
1072 | | |
1073 | | void |
1074 | | WorkerDebuggerGlobalScope::ReportError(JSContext* aCx, |
1075 | | const nsAString& aMessage) |
1076 | 0 | { |
1077 | 0 | JS::AutoFilename chars; |
1078 | 0 | uint32_t lineno = 0; |
1079 | 0 | JS::DescribeScriptedCaller(aCx, &chars, &lineno); |
1080 | 0 | nsString filename(NS_ConvertUTF8toUTF16(chars.get())); |
1081 | 0 | mWorkerPrivate->ReportErrorToDebugger(filename, lineno, aMessage); |
1082 | 0 | } |
1083 | | |
1084 | | void |
1085 | | WorkerDebuggerGlobalScope::RetrieveConsoleEvents(JSContext* aCx, |
1086 | | nsTArray<JS::Value>& aEvents, |
1087 | | ErrorResult& aRv) |
1088 | 0 | { |
1089 | 0 | WorkerGlobalScope* scope = mWorkerPrivate->GetOrCreateGlobalScope(aCx); |
1090 | 0 | if (!scope) { |
1091 | 0 | aRv.Throw(NS_ERROR_FAILURE); |
1092 | 0 | return; |
1093 | 0 | } |
1094 | 0 | |
1095 | 0 | RefPtr<Console> console = scope->GetConsole(aRv); |
1096 | 0 | if (NS_WARN_IF(aRv.Failed())) { |
1097 | 0 | return; |
1098 | 0 | } |
1099 | 0 | |
1100 | 0 | console->RetrieveConsoleEvents(aCx, aEvents, aRv); |
1101 | 0 | } |
1102 | | |
1103 | | void |
1104 | | WorkerDebuggerGlobalScope::SetConsoleEventHandler(JSContext* aCx, |
1105 | | AnyCallback* aHandler, |
1106 | | ErrorResult& aRv) |
1107 | 0 | { |
1108 | 0 | WorkerGlobalScope* scope = mWorkerPrivate->GetOrCreateGlobalScope(aCx); |
1109 | 0 | if (!scope) { |
1110 | 0 | aRv.Throw(NS_ERROR_FAILURE); |
1111 | 0 | return; |
1112 | 0 | } |
1113 | 0 | |
1114 | 0 | RefPtr<Console> console = scope->GetConsole(aRv); |
1115 | 0 | if (NS_WARN_IF(aRv.Failed())) { |
1116 | 0 | return; |
1117 | 0 | } |
1118 | 0 | |
1119 | 0 | console->SetConsoleEventHandler(aHandler); |
1120 | 0 | } |
1121 | | |
1122 | | already_AddRefed<Console> |
1123 | | WorkerDebuggerGlobalScope::GetConsole(ErrorResult& aRv) |
1124 | 0 | { |
1125 | 0 | mWorkerPrivate->AssertIsOnWorkerThread(); |
1126 | 0 |
|
1127 | 0 | // Debugger console has its own console object. |
1128 | 0 | if (!mConsole) { |
1129 | 0 | mConsole = Console::Create(mWorkerPrivate->GetJSContext(), |
1130 | 0 | nullptr, aRv); |
1131 | 0 | if (NS_WARN_IF(aRv.Failed())) { |
1132 | 0 | return nullptr; |
1133 | 0 | } |
1134 | 0 | } |
1135 | 0 | |
1136 | 0 | RefPtr<Console> console = mConsole; |
1137 | 0 | return console.forget(); |
1138 | 0 | } |
1139 | | |
1140 | | void |
1141 | | WorkerDebuggerGlobalScope::Dump(JSContext* aCx, |
1142 | | const Optional<nsAString>& aString) const |
1143 | 0 | { |
1144 | 0 | WorkerGlobalScope* scope = mWorkerPrivate->GetOrCreateGlobalScope(aCx); |
1145 | 0 | if (scope) { |
1146 | 0 | scope->Dump(aString); |
1147 | 0 | } |
1148 | 0 | } |
1149 | | |
1150 | | nsresult |
1151 | | WorkerDebuggerGlobalScope::Dispatch(TaskCategory aCategory, |
1152 | | already_AddRefed<nsIRunnable>&& aRunnable) |
1153 | 0 | { |
1154 | 0 | return EventTargetFor(aCategory)->Dispatch(std::move(aRunnable), |
1155 | 0 | NS_DISPATCH_NORMAL); |
1156 | 0 | } |
1157 | | |
1158 | | nsISerialEventTarget* |
1159 | | WorkerDebuggerGlobalScope::EventTargetFor(TaskCategory aCategory) const |
1160 | 0 | { |
1161 | 0 | return mSerialEventTarget; |
1162 | 0 | } |
1163 | | |
1164 | | AbstractThread* |
1165 | | WorkerDebuggerGlobalScope::AbstractMainThreadFor(TaskCategory aCategory) |
1166 | 0 | { |
1167 | 0 | MOZ_CRASH("AbstractMainThreadFor not supported for workers."); |
1168 | 0 | } |
1169 | | |
1170 | | bool |
1171 | | IsWorkerGlobal(JSObject* object) |
1172 | 0 | { |
1173 | 0 | return IS_INSTANCE_OF(WorkerGlobalScope, object); |
1174 | 0 | } |
1175 | | |
1176 | | bool |
1177 | | IsWorkerDebuggerGlobal(JSObject* object) |
1178 | 0 | { |
1179 | 0 | return IS_INSTANCE_OF(WorkerDebuggerGlobalScope, object); |
1180 | 0 | } |
1181 | | |
1182 | | bool |
1183 | | IsWorkerDebuggerSandbox(JSObject* object) |
1184 | 0 | { |
1185 | 0 | return SimpleGlobalObject::SimpleGlobalType(object) == |
1186 | 0 | SimpleGlobalObject::GlobalType::WorkerDebuggerSandbox; |
1187 | 0 | } |
1188 | | |
1189 | | } // dom namespace |
1190 | | } // mozilla namespace |