Unexpected constructor / instanceof behavior when retrieving indexedDB data in an...
[WebKit-https.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 "PublicURLManager.h"
43 #include "RejectedPromiseTracker.h"
44 #include "ResourceRequest.h"
45 #include "SWClientConnection.h"
46 #include "SWContextManager.h"
47 #include "SchemeRegistry.h"
48 #include "ScriptDisallowedScope.h"
49 #include "ScriptState.h"
50 #include "ServiceWorker.h"
51 #include "ServiceWorkerGlobalScope.h"
52 #include "ServiceWorkerProvider.h"
53 #include "Settings.h"
54 #include "WorkerGlobalScope.h"
55 #include "WorkerNavigator.h"
56 #include "WorkerThread.h"
57 #include "WorkletGlobalScope.h"
58 #include "WorkletScriptController.h"
59 #include <JavaScriptCore/CatchScope.h>
60 #include <JavaScriptCore/Exception.h>
61 #include <JavaScriptCore/JSPromise.h>
62 #include <JavaScriptCore/ScriptCallStack.h>
63 #include <JavaScriptCore/StrongInlines.h>
64 #include <wtf/MainThread.h>
65 #include <wtf/Ref.h>
66 #include <wtf/SetForScope.h>
67
68 namespace WebCore {
69 using namespace Inspector;
70
71 static Lock allScriptExecutionContextsMapLock;
72 static HashMap<ScriptExecutionContextIdentifier, ScriptExecutionContext*>& allScriptExecutionContextsMap()
73 {
74     static NeverDestroyed<HashMap<ScriptExecutionContextIdentifier, ScriptExecutionContext*>> contexts;
75     ASSERT(allScriptExecutionContextsMapLock.isLocked());
76     return contexts;
77 }
78
79 struct ScriptExecutionContext::PendingException {
80     WTF_MAKE_FAST_ALLOCATED;
81 public:
82     PendingException(const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL, RefPtr<ScriptCallStack>&& callStack)
83         : m_errorMessage(errorMessage)
84         , m_lineNumber(lineNumber)
85         , m_columnNumber(columnNumber)
86         , m_sourceURL(sourceURL)
87         , m_callStack(WTFMove(callStack))
88     {
89     }
90     String m_errorMessage;
91     int m_lineNumber;
92     int m_columnNumber;
93     String m_sourceURL;
94     RefPtr<ScriptCallStack> m_callStack;
95 };
96
97 ScriptExecutionContext::ScriptExecutionContext()
98 {
99 }
100
101 ScriptExecutionContextIdentifier ScriptExecutionContext::contextIdentifier() const
102 {
103     ASSERT(isContextThread());
104     if (!m_contextIdentifier) {
105         Locker<Lock> locker(allScriptExecutionContextsMapLock);
106
107         m_contextIdentifier = generateObjectIdentifier<ScriptExecutionContextIdentifierType>();
108
109         ASSERT(!allScriptExecutionContextsMap().contains(m_contextIdentifier));
110         allScriptExecutionContextsMap().add(m_contextIdentifier, const_cast<ScriptExecutionContext*>(this));
111     }
112     return m_contextIdentifier;
113 }
114
115 void ScriptExecutionContext::removeFromContextsMap()
116 {
117     if (m_contextIdentifier) {
118         Locker<Lock> locker(allScriptExecutionContextsMapLock);
119         ASSERT(allScriptExecutionContextsMap().contains(m_contextIdentifier));
120         allScriptExecutionContextsMap().remove(m_contextIdentifier);
121     }
122 }
123
124 #if ASSERT_DISABLED
125
126 inline void ScriptExecutionContext::checkConsistency() const
127 {
128 }
129
130 #else
131
132 void ScriptExecutionContext::checkConsistency() const
133 {
134     for (auto* messagePort : m_messagePorts)
135         ASSERT(messagePort->scriptExecutionContext() == this);
136
137     for (auto* destructionObserver : m_destructionObservers)
138         ASSERT(destructionObserver->scriptExecutionContext() == this);
139
140     for (auto* activeDOMObject : m_activeDOMObjects) {
141         ASSERT(activeDOMObject->scriptExecutionContext() == this);
142         activeDOMObject->assertSuspendIfNeededWasCalled();
143     }
144 }
145
146 #endif
147
148 ScriptExecutionContext::~ScriptExecutionContext()
149 {
150     checkConsistency();
151
152 #if !ASSERT_DISABLED
153     if (m_contextIdentifier) {
154         Locker<Lock> locker(allScriptExecutionContextsMapLock);
155         ASSERT_WITH_MESSAGE(!allScriptExecutionContextsMap().contains(m_contextIdentifier),
156             "A ScriptExecutionContext subclass instance implementing postTask should have already removed itself from the map");
157     }
158
159     m_inScriptExecutionContextDestructor = true;
160 #endif
161
162 #if ENABLE(SERVICE_WORKER)
163     setActiveServiceWorker(nullptr);
164 #endif
165
166     while (auto* destructionObserver = m_destructionObservers.takeAny())
167         destructionObserver->contextDestroyed();
168
169 #if !ASSERT_DISABLED
170     m_inScriptExecutionContextDestructor = false;
171 #endif
172 }
173
174 void ScriptExecutionContext::processMessageWithMessagePortsSoon()
175 {
176     if (m_willprocessMessageWithMessagePortsSoon)
177         return;
178
179     m_willprocessMessageWithMessagePortsSoon = true;
180     postTask([] (ScriptExecutionContext& context) {
181         context.dispatchMessagePortEvents();
182     });
183 }
184
185 void ScriptExecutionContext::dispatchMessagePortEvents()
186 {
187     checkConsistency();
188
189     Ref<ScriptExecutionContext> protectedThis(*this);
190     ASSERT(m_willprocessMessageWithMessagePortsSoon);
191     m_willprocessMessageWithMessagePortsSoon = false;
192
193     // Make a frozen copy of the ports so we can iterate while new ones might be added or destroyed.
194     for (auto* messagePort : copyToVector(m_messagePorts)) {
195         // The port may be destroyed, and another one created at the same address,
196         // but this is harmless. The worst that can happen as a result is that
197         // dispatchMessages() will be called needlessly.
198         if (m_messagePorts.contains(messagePort) && messagePort->started())
199             messagePort->dispatchMessages();
200     }
201 }
202
203 void ScriptExecutionContext::createdMessagePort(MessagePort& messagePort)
204 {
205     ASSERT((is<Document>(*this) && isMainThread())
206         || (is<WorkerGlobalScope>(*this) && downcast<WorkerGlobalScope>(*this).thread().thread() == &Thread::current()));
207
208     m_messagePorts.add(&messagePort);
209 }
210
211 void ScriptExecutionContext::destroyedMessagePort(MessagePort& messagePort)
212 {
213     ASSERT((is<Document>(*this) && isMainThread())
214         || (is<WorkerGlobalScope>(*this) && downcast<WorkerGlobalScope>(*this).thread().thread() == &Thread::current()));
215
216     m_messagePorts.remove(&messagePort);
217 }
218
219 void ScriptExecutionContext::didLoadResourceSynchronously()
220 {
221 }
222
223 bool ScriptExecutionContext::canSuspendActiveDOMObjectsForDocumentSuspension(Vector<ActiveDOMObject*>* unsuspendableObjects)
224 {
225     checkConsistency();
226
227     bool canSuspend = true;
228
229     forEachActiveDOMObject([&](auto& activeDOMObject) {
230         if (!activeDOMObject.canSuspendForDocumentSuspension()) {
231             canSuspend = false;
232             if (unsuspendableObjects)
233                 unsuspendableObjects->append(&activeDOMObject);
234             else
235                 return ShouldContinue::No;
236         }
237         return ShouldContinue::Yes;
238     });
239
240     if (unsuspendableObjects) {
241         // Remove activeDOMObjects that have been destroyed while we were iterating above.
242         unsuspendableObjects->removeAllMatching([&](auto* activeDOMObject) {
243             return !m_activeDOMObjects.contains(activeDOMObject);
244         });
245     }
246
247     return canSuspend;
248 }
249
250 void ScriptExecutionContext::forEachActiveDOMObject(const Function<ShouldContinue(ActiveDOMObject&)>& apply) const
251 {
252     // It is not allowed to run arbitrary script or construct new ActiveDOMObjects while we are iterating over ActiveDOMObjects.
253     // An ASSERT_WITH_SECURITY_IMPLICATION or RELEASE_ASSERT will fire if this happens, but it's important to code
254     // canSuspendActiveDOMObjectsForDocumentSuspension() / suspend() / resume() / stop() functions so it will not happen!
255     ScriptDisallowedScope scriptDisallowedScope;
256     SetForScope<bool> activeDOMObjectAdditionForbiddenScope(m_activeDOMObjectAdditionForbidden, true);
257
258     // Make a frozen copy of the objects so we can iterate while new ones might be destroyed.
259     auto possibleActiveDOMObjects = copyToVector(m_activeDOMObjects);
260
261     for (auto* activeDOMObject : possibleActiveDOMObjects) {
262         // Check if this object was deleted already. If so, just skip it.
263         // Calling contains on a possibly-already-deleted object is OK because we guarantee
264         // no new object can be added, so even if a new object ends up allocated with the
265         // same address, that will be *after* this function exits.
266         if (!m_activeDOMObjects.contains(activeDOMObject))
267             continue;
268
269         if (apply(*activeDOMObject) == ShouldContinue::No)
270             break;
271     }
272 }
273
274 void ScriptExecutionContext::suspendActiveDOMObjects(ReasonForSuspension why)
275 {
276     checkConsistency();
277
278     if (m_activeDOMObjectsAreSuspended) {
279         // A page may subsequently suspend DOM objects, say as part of entering the page cache, after the embedding
280         // client requested the page be suspended. We ignore such requests so long as the embedding client requested
281         // the suspension first. See <rdar://problem/13754896> for more details.
282         ASSERT(m_reasonForSuspendingActiveDOMObjects == ReasonForSuspension::PageWillBeSuspended);
283         return;
284     }
285
286     m_activeDOMObjectsAreSuspended = true;
287
288     forEachActiveDOMObject([why](auto& activeDOMObject) {
289         activeDOMObject.suspend(why);
290         return ShouldContinue::Yes;
291     });
292
293     m_reasonForSuspendingActiveDOMObjects = why;
294 }
295
296 void ScriptExecutionContext::resumeActiveDOMObjects(ReasonForSuspension why)
297 {
298     checkConsistency();
299
300     if (m_reasonForSuspendingActiveDOMObjects != why)
301         return;
302     m_activeDOMObjectsAreSuspended = false;
303
304     forEachActiveDOMObject([](auto& activeDOMObject) {
305         activeDOMObject.resume();
306         return ShouldContinue::Yes;
307     });
308 }
309
310 void ScriptExecutionContext::stopActiveDOMObjects()
311 {
312     checkConsistency();
313
314     if (m_activeDOMObjectsAreStopped)
315         return;
316     m_activeDOMObjectsAreStopped = true;
317
318     forEachActiveDOMObject([](auto& activeDOMObject) {
319         activeDOMObject.stop();
320         return ShouldContinue::Yes;
321     });
322 }
323
324 void ScriptExecutionContext::suspendActiveDOMObjectIfNeeded(ActiveDOMObject& activeDOMObject)
325 {
326     ASSERT(m_activeDOMObjects.contains(&activeDOMObject));
327     if (m_activeDOMObjectsAreSuspended)
328         activeDOMObject.suspend(m_reasonForSuspendingActiveDOMObjects);
329     if (m_activeDOMObjectsAreStopped)
330         activeDOMObject.stop();
331 }
332
333 void ScriptExecutionContext::didCreateActiveDOMObject(ActiveDOMObject& activeDOMObject)
334 {
335     // The m_activeDOMObjectAdditionForbidden check is a RELEASE_ASSERT because of the
336     // consequences of having an ActiveDOMObject that is not correctly reflected in the set.
337     // If we do have one of those, it can possibly be a security vulnerability. So we'd
338     // rather have a crash than continue running with the set possibly compromised.
339     ASSERT(!m_inScriptExecutionContextDestructor);
340     RELEASE_ASSERT(!m_activeDOMObjectAdditionForbidden);
341     m_activeDOMObjects.add(&activeDOMObject);
342 }
343
344 void ScriptExecutionContext::willDestroyActiveDOMObject(ActiveDOMObject& activeDOMObject)
345 {
346     m_activeDOMObjects.remove(&activeDOMObject);
347 }
348
349 void ScriptExecutionContext::didCreateDestructionObserver(ContextDestructionObserver& observer)
350 {
351     ASSERT(!m_inScriptExecutionContextDestructor);
352     m_destructionObservers.add(&observer);
353 }
354
355 void ScriptExecutionContext::willDestroyDestructionObserver(ContextDestructionObserver& observer)
356 {
357     m_destructionObservers.remove(&observer);
358 }
359
360 // FIXME: Should this function be in SecurityContext or SecurityOrigin instead?
361 bool ScriptExecutionContext::canIncludeErrorDetails(CachedScript* script, const String& sourceURL)
362 {
363     ASSERT(securityOrigin());
364     if (script) {
365         ASSERT(script->origin());
366         ASSERT(securityOrigin()->toString() == script->origin()->toString());
367         return script->isCORSSameOrigin();
368     }
369     return securityOrigin()->canRequest(completeURL(sourceURL));
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     JSC::JSValue result = promise.result(vm);
399     String resultMessage = retrieveErrorMessage(state, vm, result, scope);
400     String errorMessage = makeString("Unhandled Promise Rejection: ", resultMessage);
401     std::unique_ptr<Inspector::ConsoleMessage> message;
402     if (callStack)
403         message = std::make_unique<Inspector::ConsoleMessage>(MessageSource::JS, MessageType::Log, MessageLevel::Error, errorMessage, callStack.releaseNonNull());
404     else
405         message = std::make_unique<Inspector::ConsoleMessage>(MessageSource::JS, MessageType::Log, MessageLevel::Error, errorMessage);
406     addConsoleMessage(WTFMove(message));
407 }
408
409 void ScriptExecutionContext::addConsoleMessage(MessageSource source, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber, unsigned columnNumber, JSC::ExecState* state, unsigned long requestIdentifier)
410 {
411     addMessage(source, level, message, sourceURL, lineNumber, columnNumber, 0, state, requestIdentifier);
412 }
413
414 bool ScriptExecutionContext::dispatchErrorEvent(const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL, JSC::Exception* exception, CachedScript* cachedScript)
415 {
416     auto* target = errorEventTarget();
417     if (!target)
418         return false;
419
420     RefPtr<ErrorEvent> errorEvent;
421     if (canIncludeErrorDetails(cachedScript, sourceURL))
422         errorEvent = ErrorEvent::create(errorMessage, sourceURL, lineNumber, columnNumber, { vm(), exception ? exception->value() : JSC::jsNull() });
423     else
424         errorEvent = ErrorEvent::create("Script error."_s, { }, 0, 0, { });
425
426     ASSERT(!m_inDispatchErrorEvent);
427     m_inDispatchErrorEvent = true;
428     target->dispatchEvent(*errorEvent);
429     m_inDispatchErrorEvent = false;
430     return errorEvent->defaultPrevented();
431 }
432
433 int ScriptExecutionContext::circularSequentialID()
434 {
435     ++m_circularSequentialID;
436     if (m_circularSequentialID <= 0)
437         m_circularSequentialID = 1;
438     return m_circularSequentialID;
439 }
440
441 PublicURLManager& ScriptExecutionContext::publicURLManager()
442 {
443     if (!m_publicURLManager)
444         m_publicURLManager = PublicURLManager::create(this);
445     return *m_publicURLManager;
446 }
447
448 void ScriptExecutionContext::adjustMinimumDOMTimerInterval(Seconds oldMinimumTimerInterval)
449 {
450     if (minimumDOMTimerInterval() != oldMinimumTimerInterval) {
451         for (auto& timer : m_timeouts.values())
452             timer->updateTimerIntervalIfNecessary();
453     }
454 }
455
456 Seconds ScriptExecutionContext::minimumDOMTimerInterval() const
457 {
458     // The default implementation returns the DOMTimer's default
459     // minimum timer interval. FIXME: to make it work with dedicated
460     // workers, we will have to override it in the appropriate
461     // subclass, and provide a way to enumerate a Document's dedicated
462     // workers so we can update them all.
463     return DOMTimer::defaultMinimumInterval();
464 }
465
466 void ScriptExecutionContext::didChangeTimerAlignmentInterval()
467 {
468     for (auto& timer : m_timeouts.values())
469         timer->didChangeAlignmentInterval();
470 }
471
472 Seconds ScriptExecutionContext::domTimerAlignmentInterval(bool) const
473 {
474     return DOMTimer::defaultAlignmentInterval();
475 }
476
477 JSC::VM& ScriptExecutionContext::vm()
478 {
479     if (is<Document>(*this))
480         return commonVM();
481     if (is<WorkerGlobalScope>(*this))
482         return downcast<WorkerGlobalScope>(*this).script()->vm();
483 #if ENABLE(CSS_PAINTING_API)
484     if (is<WorkletGlobalScope>(*this))
485         return downcast<WorkletGlobalScope>(*this).script().vm();
486 #endif
487
488     RELEASE_ASSERT_NOT_REACHED();
489     return commonVM();
490 }
491
492 RejectedPromiseTracker& ScriptExecutionContext::ensureRejectedPromiseTrackerSlow()
493 {
494     // ScriptExecutionContext::vm() in Worker is only available after WorkerGlobalScope initialization is done.
495     // When initializing ScriptExecutionContext, vm() is not ready.
496
497     ASSERT(!m_rejectedPromiseTracker);
498     m_rejectedPromiseTracker = std::make_unique<RejectedPromiseTracker>(*this, vm());
499     return *m_rejectedPromiseTracker.get();
500 }
501
502 void ScriptExecutionContext::removeRejectedPromiseTracker()
503 {
504     m_rejectedPromiseTracker = nullptr;
505 }
506
507 void ScriptExecutionContext::setDatabaseContext(DatabaseContext* databaseContext)
508 {
509     m_databaseContext = databaseContext;
510 }
511
512 bool ScriptExecutionContext::hasPendingActivity() const
513 {
514     checkConsistency();
515
516     for (auto* activeDOMObject : m_activeDOMObjects) {
517         if (activeDOMObject->hasPendingActivity())
518             return true;
519     }
520
521     return false;
522 }
523
524 JSC::ExecState* ScriptExecutionContext::execState()
525 {
526     if (is<Document>(*this)) {
527         Document& document = downcast<Document>(*this);
528         auto* frame = document.frame();
529         return frame ? frame->script().globalObject(mainThreadNormalWorld())->globalExec() : nullptr;
530     }
531
532     if (is<WorkerGlobalScope>(*this))
533         return execStateFromWorkerGlobalScope(downcast<WorkerGlobalScope>(*this));
534 #if ENABLE(CSS_PAINTING_API)
535     if (is<WorkletGlobalScope>(*this))
536         return execStateFromWorkletGlobalScope(downcast<WorkletGlobalScope>(*this));
537 #endif
538
539     ASSERT_NOT_REACHED();
540     return nullptr;
541 }
542
543 String ScriptExecutionContext::domainForCachePartition() const
544 {
545     return m_domainForCachePartition.isNull() ? topOrigin().domainForCachePartition() : m_domainForCachePartition;
546 }
547
548 bool ScriptExecutionContext::hasServiceWorkerScheme()
549 {
550     ASSERT(securityOrigin());
551     return SchemeRegistry::isServiceWorkerContainerCustomScheme(securityOrigin()->protocol());
552 }
553
554 #if ENABLE(SERVICE_WORKER)
555
556 ServiceWorker* ScriptExecutionContext::activeServiceWorker() const
557 {
558     return m_activeServiceWorker.get();
559 }
560
561 void ScriptExecutionContext::setActiveServiceWorker(RefPtr<ServiceWorker>&& serviceWorker)
562 {
563     m_activeServiceWorker = WTFMove(serviceWorker);
564 }
565
566 void ScriptExecutionContext::registerServiceWorker(ServiceWorker& serviceWorker)
567 {
568     auto addResult = m_serviceWorkers.add(serviceWorker.identifier(), &serviceWorker);
569     ASSERT_UNUSED(addResult, addResult.isNewEntry);
570 }
571
572 void ScriptExecutionContext::unregisterServiceWorker(ServiceWorker& serviceWorker)
573 {
574     m_serviceWorkers.remove(serviceWorker.identifier());
575 }
576
577 ServiceWorkerContainer* ScriptExecutionContext::serviceWorkerContainer()
578 {
579     NavigatorBase* navigator = nullptr;
580     if (is<Document>(*this)) {
581         if (auto* window = downcast<Document>(*this).domWindow())
582             navigator = window->optionalNavigator();
583     } else
584         navigator = downcast<WorkerGlobalScope>(*this).optionalNavigator();
585
586     return navigator ? &navigator->serviceWorker() : nullptr;
587 }
588
589 bool ScriptExecutionContext::postTaskTo(const DocumentOrWorkerIdentifier& contextIdentifier, WTF::Function<void(ScriptExecutionContext&)>&& task)
590 {
591     ASSERT(isMainThread());
592
593     bool wasPosted = false;
594     switchOn(contextIdentifier, [&] (DocumentIdentifier identifier) {
595         auto* document = Document::allDocumentsMap().get(identifier);
596         if (!document)
597             return;
598         document->postTask([task = WTFMove(task)](auto& scope) {
599             task(scope);
600         });
601         wasPosted= true;
602     }, [&](ServiceWorkerIdentifier identifier) {
603         wasPosted = SWContextManager::singleton().postTaskToServiceWorker(identifier, [task = WTFMove(task)](auto& scope) {
604             task(scope);
605         });
606     });
607     return wasPosted;
608 }
609
610 #endif
611
612 bool ScriptExecutionContext::postTaskTo(ScriptExecutionContextIdentifier identifier, Task&& task)
613 {
614     Locker<Lock> locker(allScriptExecutionContextsMapLock);
615     auto* context = allScriptExecutionContextsMap().get(identifier);
616
617     if (!context)
618         return false;
619
620     context->postTask(WTFMove(task));
621     return true;
622 }
623
624 } // namespace WebCore