WTF shouldn't have both Thread and ThreadIdentifier
[WebKit.git] / Source / WebCore / dom / ScriptExecutionContext.cpp
1 /*
2  * Copyright (C) 2008 Apple Inc. All Rights Reserved.
3  * Copyright (C) 2012 Google Inc. All Rights Reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  */
27
28 #include "config.h"
29 #include "ScriptExecutionContext.h"
30
31 #include "CachedScript.h"
32 #include "CommonVM.h"
33 #include "DOMTimer.h"
34 #include "DOMWindow.h"
35 #include "DatabaseContext.h"
36 #include "Document.h"
37 #include "ErrorEvent.h"
38 #include "JSDOMExceptionHandling.h"
39 #include "JSDOMWindow.h"
40 #include "MessagePort.h"
41 #include "Navigator.h"
42 #include "NoEventDispatchAssertion.h"
43 #include "PublicURLManager.h"
44 #include "RejectedPromiseTracker.h"
45 #include "ResourceRequest.h"
46 #include "SWClientConnection.h"
47 #include "ScriptState.h"
48 #include "ServiceWorker.h"
49 #include "ServiceWorkerProvider.h"
50 #include "Settings.h"
51 #include "WorkerGlobalScope.h"
52 #include "WorkerNavigator.h"
53 #include "WorkerThread.h"
54 #include <heap/StrongInlines.h>
55 #include <inspector/ScriptCallStack.h>
56 #include <runtime/CatchScope.h>
57 #include <runtime/Exception.h>
58 #include <runtime/JSPromise.h>
59 #include <wtf/MainThread.h>
60 #include <wtf/Ref.h>
61
62
63 namespace WebCore {
64 using namespace Inspector;
65
66 struct ScriptExecutionContext::PendingException {
67     WTF_MAKE_FAST_ALLOCATED;
68 public:
69     PendingException(const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL, RefPtr<ScriptCallStack>&& callStack)
70         : m_errorMessage(errorMessage)
71         , m_lineNumber(lineNumber)
72         , m_columnNumber(columnNumber)
73         , m_sourceURL(sourceURL)
74         , m_callStack(WTFMove(callStack))
75     {
76     }
77     String m_errorMessage;
78     int m_lineNumber;
79     int m_columnNumber;
80     String m_sourceURL;
81     RefPtr<ScriptCallStack> m_callStack;
82 };
83
84 ScriptExecutionContext::ScriptExecutionContext()
85 {
86 }
87
88 #if ASSERT_DISABLED
89
90 inline void ScriptExecutionContext::checkConsistency() const
91 {
92 }
93
94 #else
95
96 void ScriptExecutionContext::checkConsistency() const
97 {
98     for (auto* messagePort : m_messagePorts)
99         ASSERT(messagePort->scriptExecutionContext() == this);
100
101     for (auto* destructionObserver : m_destructionObservers)
102         ASSERT(destructionObserver->scriptExecutionContext() == this);
103
104     for (auto* activeDOMObject : m_activeDOMObjects) {
105         ASSERT(activeDOMObject->scriptExecutionContext() == this);
106         activeDOMObject->assertSuspendIfNeededWasCalled();
107     }
108 }
109
110 #endif
111
112 ScriptExecutionContext::~ScriptExecutionContext()
113 {
114     checkConsistency();
115
116 #if !ASSERT_DISABLED
117     m_inScriptExecutionContextDestructor = true;
118 #endif
119
120 #if ENABLE(SERVICE_WORKER)
121     setActiveServiceWorker(nullptr);
122 #endif
123
124     while (auto* destructionObserver = m_destructionObservers.takeAny())
125         destructionObserver->contextDestroyed();
126
127     for (auto* messagePort : m_messagePorts)
128         messagePort->contextDestroyed();
129
130 #if !ASSERT_DISABLED
131     m_inScriptExecutionContextDestructor = false;
132 #endif
133 }
134
135 void ScriptExecutionContext::processMessagePortMessagesSoon()
136 {
137     if (m_willProcessMessagePortMessagesSoon)
138         return;
139
140     m_willProcessMessagePortMessagesSoon = true;
141     postTask([] (ScriptExecutionContext& context) {
142         context.dispatchMessagePortEvents();
143     });
144 }
145
146 void ScriptExecutionContext::dispatchMessagePortEvents()
147 {
148     checkConsistency();
149
150     Ref<ScriptExecutionContext> protectedThis(*this);
151     ASSERT(m_willProcessMessagePortMessagesSoon);
152     m_willProcessMessagePortMessagesSoon = false;
153
154     // Make a frozen copy of the ports so we can iterate while new ones might be added or destroyed.
155     for (auto* messagePort : copyToVector(m_messagePorts)) {
156         // The port may be destroyed, and another one created at the same address,
157         // but this is harmless. The worst that can happen as a result is that
158         // dispatchMessages() will be called needlessly.
159         if (m_messagePorts.contains(messagePort) && messagePort->started())
160             messagePort->dispatchMessages();
161     }
162 }
163
164 void ScriptExecutionContext::createdMessagePort(MessagePort& messagePort)
165 {
166     ASSERT((is<Document>(*this) && isMainThread())
167         || (is<WorkerGlobalScope>(*this) && downcast<WorkerGlobalScope>(*this).thread().thread() == &Thread::current()));
168
169     m_messagePorts.add(&messagePort);
170 }
171
172 void ScriptExecutionContext::destroyedMessagePort(MessagePort& messagePort)
173 {
174     ASSERT((is<Document>(*this) && isMainThread())
175         || (is<WorkerGlobalScope>(*this) && downcast<WorkerGlobalScope>(*this).thread().thread() == &Thread::current()));
176
177     m_messagePorts.remove(&messagePort);
178 }
179
180 void ScriptExecutionContext::didLoadResourceSynchronously()
181 {
182 }
183
184 bool ScriptExecutionContext::canSuspendActiveDOMObjectsForDocumentSuspension(Vector<ActiveDOMObject*>* unsuspendableObjects)
185 {
186     checkConsistency();
187
188     bool canSuspend = true;
189
190     m_activeDOMObjectAdditionForbidden = true;
191 #if !ASSERT_DISABLED || ENABLE(SECURITY_ASSERTIONS)
192     m_activeDOMObjectRemovalForbidden = true;
193 #endif
194
195     // We assume that m_activeDOMObjects will not change during iteration: canSuspend
196     // functions should not add new active DOM objects, nor execute arbitrary JavaScript.
197     // An ASSERT_WITH_SECURITY_IMPLICATION or RELEASE_ASSERT will fire if this happens, but it's important to code
198     // canSuspend functions so it will not happen!
199     NoEventDispatchAssertion::InMainThread assertNoEventDispatch;
200     for (auto* activeDOMObject : m_activeDOMObjects) {
201         if (!activeDOMObject->canSuspendForDocumentSuspension()) {
202             canSuspend = false;
203             if (unsuspendableObjects)
204                 unsuspendableObjects->append(activeDOMObject);
205             else
206                 break;
207         }
208     }
209
210     m_activeDOMObjectAdditionForbidden = false;
211 #if !ASSERT_DISABLED || ENABLE(SECURITY_ASSERTIONS)
212     m_activeDOMObjectRemovalForbidden = false;
213 #endif
214
215     return canSuspend;
216 }
217
218 void ScriptExecutionContext::suspendActiveDOMObjects(ActiveDOMObject::ReasonForSuspension why)
219 {
220     checkConsistency();
221
222     if (m_activeDOMObjectsAreSuspended) {
223         // A page may subsequently suspend DOM objects, say as part of entering the page cache, after the embedding
224         // client requested the page be suspended. We ignore such requests so long as the embedding client requested
225         // the suspension first. See <rdar://problem/13754896> for more details.
226         ASSERT(m_reasonForSuspendingActiveDOMObjects == ActiveDOMObject::PageWillBeSuspended);
227         return;
228     }
229
230     m_activeDOMObjectsAreSuspended = true;
231
232     m_activeDOMObjectAdditionForbidden = true;
233 #if !ASSERT_DISABLED || ENABLE(SECURITY_ASSERTIONS)
234     m_activeDOMObjectRemovalForbidden = true;
235 #endif
236
237     // We assume that m_activeDOMObjects will not change during iteration: suspend
238     // functions should not add new active DOM objects, nor execute arbitrary JavaScript.
239     // An ASSERT_WITH_SECURITY_IMPLICATION or RELEASE_ASSERT will fire if this happens, but it's important to code
240     // suspend functions so it will not happen!
241     NoEventDispatchAssertion::InMainThread assertNoEventDispatch;
242     for (auto* activeDOMObject : m_activeDOMObjects)
243         activeDOMObject->suspend(why);
244
245     m_activeDOMObjectAdditionForbidden = false;
246 #if !ASSERT_DISABLED || ENABLE(SECURITY_ASSERTIONS)
247     m_activeDOMObjectRemovalForbidden = false;
248 #endif
249
250     m_reasonForSuspendingActiveDOMObjects = why;
251 }
252
253 void ScriptExecutionContext::resumeActiveDOMObjects(ActiveDOMObject::ReasonForSuspension why)
254 {
255     checkConsistency();
256
257     if (m_reasonForSuspendingActiveDOMObjects != why)
258         return;
259     m_activeDOMObjectsAreSuspended = false;
260
261     m_activeDOMObjectAdditionForbidden = true;
262 #if !ASSERT_DISABLED || ENABLE(SECURITY_ASSERTIONS)
263     m_activeDOMObjectRemovalForbidden = true;
264 #endif
265
266     // We assume that m_activeDOMObjects will not change during iteration: resume
267     // functions should not add new active DOM objects, nor execute arbitrary JavaScript.
268     // An ASSERT_WITH_SECURITY_IMPLICATION or RELEASE_ASSERT will fire if this happens, but it's important to code
269     // resume functions so it will not happen!
270     NoEventDispatchAssertion::InMainThread assertNoEventDispatch;
271     for (auto* activeDOMObject : m_activeDOMObjects)
272         activeDOMObject->resume();
273
274     m_activeDOMObjectAdditionForbidden = false;
275 #if !ASSERT_DISABLED || ENABLE(SECURITY_ASSERTIONS)
276     m_activeDOMObjectRemovalForbidden = false;
277 #endif
278 }
279
280 void ScriptExecutionContext::stopActiveDOMObjects()
281 {
282     checkConsistency();
283
284     if (m_activeDOMObjectsAreStopped)
285         return;
286     m_activeDOMObjectsAreStopped = true;
287
288     // Make a frozen copy of the objects so we can iterate while new ones might be destroyed.
289     auto possibleActiveDOMObjects = copyToVector(m_activeDOMObjects);
290
291     m_activeDOMObjectAdditionForbidden = true;
292
293     // We assume that new objects will not be added to m_activeDOMObjects during iteration:
294     // stop functions should not add new active DOM objects, nor execute arbitrary JavaScript.
295     // An ASSERT_WITH_SECURITY_IMPLICATION or RELEASE_ASSERT will fire if this happens, but it's important to code stop functions
296     // so it will not happen!
297     NoEventDispatchAssertion assertNoEventDispatch;
298     for (auto* activeDOMObject : possibleActiveDOMObjects) {
299         // Check if this object was deleted already. If so, just skip it.
300         // Calling contains on a possibly-already-deleted object is OK because we guarantee
301         // no new object can be added, so even if a new object ends up allocated with the
302         // same address, that will be *after* this function exits.
303         if (!m_activeDOMObjects.contains(activeDOMObject))
304             continue;
305         activeDOMObject->stop();
306     }
307
308     m_activeDOMObjectAdditionForbidden = false;
309
310     // FIXME: Make message ports be active DOM objects and let them implement stop instead
311     // of having this separate mechanism just for them.
312     for (auto* messagePort : m_messagePorts)
313         messagePort->close();
314 }
315
316 void ScriptExecutionContext::suspendActiveDOMObjectIfNeeded(ActiveDOMObject& activeDOMObject)
317 {
318     ASSERT(m_activeDOMObjects.contains(&activeDOMObject));
319     if (m_activeDOMObjectsAreSuspended)
320         activeDOMObject.suspend(m_reasonForSuspendingActiveDOMObjects);
321     if (m_activeDOMObjectsAreStopped)
322         activeDOMObject.stop();
323 }
324
325 void ScriptExecutionContext::didCreateActiveDOMObject(ActiveDOMObject& activeDOMObject)
326 {
327     // The m_activeDOMObjectAdditionForbidden check is a RELEASE_ASSERT because of the
328     // consequences of having an ActiveDOMObject that is not correctly reflected in the set.
329     // If we do have one of those, it can possibly be a security vulnerability. So we'd
330     // rather have a crash than continue running with the set possibly compromised.
331     ASSERT(!m_inScriptExecutionContextDestructor);
332     RELEASE_ASSERT(!m_activeDOMObjectAdditionForbidden);
333     m_activeDOMObjects.add(&activeDOMObject);
334 }
335
336 void ScriptExecutionContext::willDestroyActiveDOMObject(ActiveDOMObject& activeDOMObject)
337 {
338     ASSERT_WITH_SECURITY_IMPLICATION(!m_activeDOMObjectRemovalForbidden);
339     m_activeDOMObjects.remove(&activeDOMObject);
340 }
341
342 void ScriptExecutionContext::didCreateDestructionObserver(ContextDestructionObserver& observer)
343 {
344     ASSERT(!m_inScriptExecutionContextDestructor);
345     m_destructionObservers.add(&observer);
346 }
347
348 void ScriptExecutionContext::willDestroyDestructionObserver(ContextDestructionObserver& observer)
349 {
350     m_destructionObservers.remove(&observer);
351 }
352
353 bool ScriptExecutionContext::sanitizeScriptError(String& errorMessage, int& lineNumber, int& columnNumber, String& sourceURL, JSC::Strong<JSC::Unknown>& error, CachedScript* cachedScript)
354 {
355     ASSERT(securityOrigin());
356     if (cachedScript) {
357         ASSERT(cachedScript->origin());
358         ASSERT(securityOrigin()->toString() == cachedScript->origin()->toString());
359         if (cachedScript->isCORSSameOrigin())
360             return false;
361     } else if (securityOrigin()->canRequest(completeURL(sourceURL)))
362         return false;
363
364     errorMessage = ASCIILiteral { "Script error." };
365     sourceURL = { };
366     lineNumber = 0;
367     columnNumber = 0;
368     error = { };
369     return true;
370 }
371
372 void ScriptExecutionContext::reportException(const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL, JSC::Exception* exception, RefPtr<ScriptCallStack>&& callStack, CachedScript* cachedScript)
373 {
374     if (m_inDispatchErrorEvent) {
375         if (!m_pendingExceptions)
376             m_pendingExceptions = std::make_unique<Vector<std::unique_ptr<PendingException>>>();
377         m_pendingExceptions->append(std::make_unique<PendingException>(errorMessage, lineNumber, columnNumber, sourceURL, WTFMove(callStack)));
378         return;
379     }
380
381     // First report the original exception and only then all the nested ones.
382     if (!dispatchErrorEvent(errorMessage, lineNumber, columnNumber, sourceURL, exception, cachedScript))
383         logExceptionToConsole(errorMessage, sourceURL, lineNumber, columnNumber, callStack.copyRef());
384
385     if (!m_pendingExceptions)
386         return;
387
388     auto pendingExceptions = WTFMove(m_pendingExceptions);
389     for (auto& exception : *pendingExceptions)
390         logExceptionToConsole(exception->m_errorMessage, exception->m_sourceURL, exception->m_lineNumber, exception->m_columnNumber, WTFMove(exception->m_callStack));
391 }
392
393 void ScriptExecutionContext::reportUnhandledPromiseRejection(JSC::ExecState& state, JSC::JSPromise& promise, RefPtr<Inspector::ScriptCallStack>&& callStack)
394 {
395     JSC::VM& vm = state.vm();
396     auto scope = DECLARE_CATCH_SCOPE(vm);
397
398     int lineNumber = 0;
399     int columnNumber = 0;
400     String sourceURL;
401
402     JSC::JSValue result = promise.result(vm);
403     String resultMessage = retrieveErrorMessage(state, vm, result, scope);
404     String errorMessage = makeString("Unhandled Promise Rejection: ", resultMessage);
405     if (callStack) {
406         if (const ScriptCallFrame* callFrame = callStack->firstNonNativeCallFrame()) {
407             lineNumber = callFrame->lineNumber();
408             columnNumber = callFrame->columnNumber();
409             sourceURL = callFrame->sourceURL();
410         }
411     }
412
413     logExceptionToConsole(errorMessage, sourceURL, lineNumber, columnNumber, WTFMove(callStack));
414 }
415
416 void ScriptExecutionContext::addConsoleMessage(MessageSource source, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber, unsigned columnNumber, JSC::ExecState* state, unsigned long requestIdentifier)
417 {
418     addMessage(source, level, message, sourceURL, lineNumber, columnNumber, 0, state, requestIdentifier);
419 }
420
421 bool ScriptExecutionContext::dispatchErrorEvent(const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL, JSC::Exception* exception, CachedScript* cachedScript)
422 {
423     EventTarget* target = errorEventTarget();
424     if (!target)
425         return false;
426
427     String message = errorMessage;
428     int line = lineNumber;
429     int column = columnNumber;
430     String sourceName = sourceURL;
431     JSC::Strong<JSC::Unknown> error = exception && exception->value() ? JSC::Strong<JSC::Unknown>(vm(), exception->value()) : JSC::Strong<JSC::Unknown>();
432     sanitizeScriptError(message, line, column, sourceName, error, cachedScript);
433
434     ASSERT(!m_inDispatchErrorEvent);
435     m_inDispatchErrorEvent = true;
436     Ref<ErrorEvent> errorEvent = ErrorEvent::create(message, sourceName, line, column, error);
437     target->dispatchEvent(errorEvent);
438     m_inDispatchErrorEvent = false;
439     return errorEvent->defaultPrevented();
440 }
441
442 int ScriptExecutionContext::circularSequentialID()
443 {
444     ++m_circularSequentialID;
445     if (m_circularSequentialID <= 0)
446         m_circularSequentialID = 1;
447     return m_circularSequentialID;
448 }
449
450 PublicURLManager& ScriptExecutionContext::publicURLManager()
451 {
452     if (!m_publicURLManager)
453         m_publicURLManager = PublicURLManager::create(this);
454     return *m_publicURLManager;
455 }
456
457 void ScriptExecutionContext::adjustMinimumDOMTimerInterval(Seconds oldMinimumTimerInterval)
458 {
459     if (minimumDOMTimerInterval() != oldMinimumTimerInterval) {
460         for (auto& timer : m_timeouts.values())
461             timer->updateTimerIntervalIfNecessary();
462     }
463 }
464
465 Seconds ScriptExecutionContext::minimumDOMTimerInterval() const
466 {
467     // The default implementation returns the DOMTimer's default
468     // minimum timer interval. FIXME: to make it work with dedicated
469     // workers, we will have to override it in the appropriate
470     // subclass, and provide a way to enumerate a Document's dedicated
471     // workers so we can update them all.
472     return DOMTimer::defaultMinimumInterval();
473 }
474
475 void ScriptExecutionContext::didChangeTimerAlignmentInterval()
476 {
477     for (auto& timer : m_timeouts.values())
478         timer->didChangeAlignmentInterval();
479 }
480
481 Seconds ScriptExecutionContext::domTimerAlignmentInterval(bool) const
482 {
483     return DOMTimer::defaultAlignmentInterval();
484 }
485
486 JSC::VM& ScriptExecutionContext::vm()
487 {
488     if (is<Document>(*this))
489         return commonVM();
490
491     return downcast<WorkerGlobalScope>(*this).script()->vm();
492 }
493
494 RejectedPromiseTracker& ScriptExecutionContext::ensureRejectedPromiseTrackerSlow()
495 {
496     // ScriptExecutionContext::vm() in Worker is only available after WorkerGlobalScope initialization is done.
497     // When initializing ScriptExecutionContext, vm() is not ready.
498
499     ASSERT(!m_rejectedPromiseTracker);
500     m_rejectedPromiseTracker = std::make_unique<RejectedPromiseTracker>(*this, vm());
501     return *m_rejectedPromiseTracker.get();
502 }
503
504 void ScriptExecutionContext::setDatabaseContext(DatabaseContext* databaseContext)
505 {
506     m_databaseContext = databaseContext;
507 }
508
509 bool ScriptExecutionContext::hasPendingActivity() const
510 {
511     checkConsistency();
512
513     for (auto* activeDOMObject : m_activeDOMObjects) {
514         if (activeDOMObject->hasPendingActivity())
515             return true;
516     }
517
518     for (auto* messagePort : m_messagePorts) {
519         if (messagePort->hasPendingActivity())
520             return true;
521     }
522
523     return false;
524 }
525
526 JSC::ExecState* ScriptExecutionContext::execState()
527 {
528     if (is<Document>(*this)) {
529         Document& document = downcast<Document>(*this);
530         return execStateFromPage(mainThreadNormalWorld(), document.page());
531     }
532
533     WorkerGlobalScope* workerGlobalScope = static_cast<WorkerGlobalScope*>(this);
534     return execStateFromWorkerGlobalScope(workerGlobalScope);
535 }
536
537 #if ENABLE(SERVICE_WORKER)
538
539 ServiceWorker* ScriptExecutionContext::activeServiceWorker() const
540 {
541     return m_activeServiceWorker.get();
542 }
543
544 void ScriptExecutionContext::setActiveServiceWorker(RefPtr<ServiceWorker>&& serviceWorker)
545 {
546     // Add support for workers.
547     if (!is<Document>(*this))
548         return;
549
550     if (m_activeServiceWorker == serviceWorker)
551         return;
552
553     auto& connection = ServiceWorkerProvider::singleton().serviceWorkerConnectionForSession(sessionID());
554     if (m_activeServiceWorker)
555         connection.serviceWorkerStoppedControllingClient(m_activeServiceWorker->identifier(), m_activeServiceWorker->registrationIdentifier(), downcast<Document>(*this).identifier());
556
557     m_activeServiceWorker = WTFMove(serviceWorker);
558
559     if (m_activeServiceWorker)
560         connection.serviceWorkerStartedControllingClient(m_activeServiceWorker->identifier(), m_activeServiceWorker->registrationIdentifier(), downcast<Document>(*this).identifier());
561 }
562
563 void ScriptExecutionContext::registerServiceWorker(ServiceWorker& serviceWorker)
564 {
565     auto addResult = m_serviceWorkers.add(serviceWorker.identifier(), &serviceWorker);
566     ASSERT_UNUSED(addResult, addResult.isNewEntry);
567 }
568
569 void ScriptExecutionContext::unregisterServiceWorker(ServiceWorker& serviceWorker)
570 {
571     m_serviceWorkers.remove(serviceWorker.identifier());
572 }
573
574 ServiceWorkerContainer* ScriptExecutionContext::serviceWorkerContainer()
575 {
576     NavigatorBase* navigator = nullptr;
577     if (is<Document>(*this)) {
578         if (auto* window = downcast<Document>(*this).domWindow())
579             navigator = window->optionalNavigator();
580     } else
581         navigator = downcast<WorkerGlobalScope>(*this).optionalNavigator();
582
583     return navigator ? &navigator->serviceWorker() : nullptr;
584 }
585 #endif
586
587 } // namespace WebCore