2 * Copyright (C) 2008 Apple Inc. All Rights Reserved.
3 * Copyright (C) 2012 Google Inc. All Rights Reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, 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 COMPUTER, 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.
29 #include "core/dom/ExecutionContext.h"
31 #include "core/dom/ExecutionContextTask.h"
32 #include "core/events/ErrorEvent.h"
33 #include "core/events/EventTarget.h"
34 #include "core/fetch/MemoryCache.h"
35 #include "core/frame/UseCounter.h"
36 #include "core/html/PublicURLManager.h"
37 #include "core/inspector/InspectorInstrumentation.h"
38 #include "core/inspector/ScriptCallStack.h"
39 #include "core/workers/WorkerGlobalScope.h"
40 #include "core/workers/WorkerThread.h"
41 #include "platform/RuntimeEnabledFeatures.h"
42 #include "wtf/MainThread.h"
46 class ExecutionContext::PendingException
: public NoBaseWillBeGarbageCollectedFinalized
<ExecutionContext::PendingException
> {
47 WTF_MAKE_NONCOPYABLE(PendingException
);
49 PendingException(const String
& errorMessage
, int lineNumber
, int columnNumber
, int scriptId
, const String
& sourceURL
, PassRefPtrWillBeRawPtr
<ScriptCallStack
> callStack
)
50 : m_errorMessage(errorMessage
)
51 , m_lineNumber(lineNumber
)
52 , m_columnNumber(columnNumber
)
53 , m_scriptId(scriptId
)
54 , m_sourceURL(sourceURL
)
55 , m_callStack(callStack
)
60 visitor
->trace(m_callStack
);
62 String m_errorMessage
;
67 RefPtrWillBeMember
<ScriptCallStack
> m_callStack
;
70 ExecutionContext::ExecutionContext()
71 : m_circularSequentialID(0)
72 , m_inDispatchErrorEvent(false)
73 , m_activeDOMObjectsAreSuspended(false)
74 , m_activeDOMObjectsAreStopped(false)
75 , m_strictMixedContentCheckingEnforced(false)
76 , m_windowInteractionTokens(0)
77 , m_isRunSuspendableTasksScheduled(false)
78 , m_referrerPolicy(ReferrerPolicyDefault
)
82 ExecutionContext::~ExecutionContext()
86 void ExecutionContext::suspendActiveDOMObjects()
88 ASSERT(!m_activeDOMObjectsAreSuspended
);
89 notifySuspendingActiveDOMObjects();
90 m_activeDOMObjectsAreSuspended
= true;
93 void ExecutionContext::resumeActiveDOMObjects()
95 ASSERT(m_activeDOMObjectsAreSuspended
);
96 m_activeDOMObjectsAreSuspended
= false;
97 notifyResumingActiveDOMObjects();
100 void ExecutionContext::stopActiveDOMObjects()
102 m_activeDOMObjectsAreStopped
= true;
103 notifyStoppingActiveDOMObjects();
106 void ExecutionContext::postSuspendableTask(PassOwnPtr
<SuspendableTask
> task
)
108 m_suspendedTasks
.append(task
);
109 if (!m_activeDOMObjectsAreSuspended
)
110 postTask(FROM_HERE
, createSameThreadTask(&ExecutionContext::runSuspendableTasks
, this));
113 void ExecutionContext::notifyContextDestroyed()
115 Deque
<OwnPtr
<SuspendableTask
>> suspendedTasks
;
116 suspendedTasks
.swap(m_suspendedTasks
);
117 for (Deque
<OwnPtr
<SuspendableTask
>>::iterator it
= suspendedTasks
.begin(); it
!= suspendedTasks
.end(); ++it
)
118 (*it
)->contextDestroyed();
119 ContextLifecycleNotifier::notifyContextDestroyed();
122 void ExecutionContext::suspendScheduledTasks()
124 suspendActiveDOMObjects();
125 tasksWereSuspended();
128 void ExecutionContext::resumeScheduledTasks()
130 resumeActiveDOMObjects();
132 // We need finish stack unwiding before running next task because it can suspend this context.
133 if (m_isRunSuspendableTasksScheduled
)
135 m_isRunSuspendableTasksScheduled
= true;
136 postTask(FROM_HERE
, createSameThreadTask(&ExecutionContext::runSuspendableTasks
, this));
139 void ExecutionContext::suspendActiveDOMObjectIfNeeded(ActiveDOMObject
* object
)
141 ASSERT(contains(object
));
142 // Ensure all ActiveDOMObjects are suspended also newly created ones.
143 if (m_activeDOMObjectsAreSuspended
)
147 bool ExecutionContext::shouldSanitizeScriptError(const String
& sourceURL
, AccessControlStatus corsStatus
)
149 if (corsStatus
== OpaqueResource
)
151 return !(securityOrigin()->canRequestNoSuborigin(completeURL(sourceURL
)) || corsStatus
== SharableCrossOrigin
);
154 void ExecutionContext::reportException(PassRefPtrWillBeRawPtr
<ErrorEvent
> event
, int scriptId
, PassRefPtrWillBeRawPtr
<ScriptCallStack
> callStack
, AccessControlStatus corsStatus
)
156 RefPtrWillBeRawPtr
<ErrorEvent
> errorEvent
= event
;
157 if (m_inDispatchErrorEvent
) {
158 if (!m_pendingExceptions
)
159 m_pendingExceptions
= adoptPtrWillBeNoop(new WillBeHeapVector
<OwnPtrWillBeMember
<PendingException
>>());
160 m_pendingExceptions
->append(adoptPtrWillBeNoop(new PendingException(errorEvent
->messageForConsole(), errorEvent
->lineno(), errorEvent
->colno(), scriptId
, errorEvent
->filename(), callStack
)));
164 // First report the original exception and only then all the nested ones.
165 if (!dispatchErrorEvent(errorEvent
, corsStatus
))
166 logExceptionToConsole(errorEvent
->messageForConsole(), scriptId
, errorEvent
->filename(), errorEvent
->lineno(), errorEvent
->colno(), callStack
);
168 if (!m_pendingExceptions
)
171 for (size_t i
= 0; i
< m_pendingExceptions
->size(); i
++) {
172 PendingException
* e
= m_pendingExceptions
->at(i
).get();
173 logExceptionToConsole(e
->m_errorMessage
, e
->m_scriptId
, e
->m_sourceURL
, e
->m_lineNumber
, e
->m_columnNumber
, e
->m_callStack
);
175 m_pendingExceptions
.clear();
178 bool ExecutionContext::dispatchErrorEvent(PassRefPtrWillBeRawPtr
<ErrorEvent
> event
, AccessControlStatus corsStatus
)
180 EventTarget
* target
= errorEventTarget();
184 RefPtrWillBeRawPtr
<ErrorEvent
> errorEvent
= event
;
185 if (shouldSanitizeScriptError(errorEvent
->filename(), corsStatus
))
186 errorEvent
= ErrorEvent::createSanitizedError(errorEvent
->world());
188 ASSERT(!m_inDispatchErrorEvent
);
189 m_inDispatchErrorEvent
= true;
190 target
->dispatchEvent(errorEvent
);
191 m_inDispatchErrorEvent
= false;
192 return errorEvent
->defaultPrevented();
195 void ExecutionContext::runSuspendableTasks()
197 m_isRunSuspendableTasksScheduled
= false;
198 while (!m_activeDOMObjectsAreSuspended
&& m_suspendedTasks
.size()) {
199 OwnPtr
<SuspendableTask
> task
= m_suspendedTasks
.takeFirst();
204 int ExecutionContext::circularSequentialID()
206 ++m_circularSequentialID
;
207 if (m_circularSequentialID
> ((1U << 31) - 1U))
208 m_circularSequentialID
= 1;
210 return m_circularSequentialID
;
213 PublicURLManager
& ExecutionContext::publicURLManager()
215 if (!m_publicURLManager
)
216 m_publicURLManager
= PublicURLManager::create(this);
217 return *m_publicURLManager
;
220 SecurityOrigin
* ExecutionContext::securityOrigin()
222 return securityContext().securityOrigin();
225 ContentSecurityPolicy
* ExecutionContext::contentSecurityPolicy()
227 return securityContext().contentSecurityPolicy();
230 const KURL
& ExecutionContext::url() const
235 KURL
ExecutionContext::completeURL(const String
& url
) const
237 return virtualCompleteURL(url
);
240 bool ExecutionContext::hasSuborigin()
242 return securityContext().securityOrigin()->hasSuborigin();
245 String
ExecutionContext::suboriginName()
247 return securityContext().securityOrigin()->suboriginName();
250 void ExecutionContext::allowWindowInteraction()
252 ++m_windowInteractionTokens
;
255 void ExecutionContext::consumeWindowInteraction()
257 if (m_windowInteractionTokens
== 0)
259 --m_windowInteractionTokens
;
262 bool ExecutionContext::isWindowInteractionAllowed() const
264 return m_windowInteractionTokens
> 0;
267 void ExecutionContext::setReferrerPolicy(ReferrerPolicy referrerPolicy
)
269 // FIXME: Can we adopt the CSP referrer policy merge algorithm? Or does the web rely on being able to modify the referrer policy in-flight?
270 UseCounter::count(this, UseCounter::SetReferrerPolicy
);
271 if (m_referrerPolicy
!= ReferrerPolicyDefault
)
272 UseCounter::count(this, UseCounter::ResetReferrerPolicy
);
274 m_referrerPolicy
= referrerPolicy
;
277 void ExecutionContext::removeURLFromMemoryCache(const KURL
& url
)
279 memoryCache()->removeURLFromCache(url
);
282 // |name| should be non-empty, and this should be enforced by parsing.
283 void ExecutionContext::enforceSuborigin(const String
& name
)
287 ASSERT(!name
.isEmpty());
288 ASSERT(RuntimeEnabledFeatures::suboriginsEnabled());
289 SecurityOrigin
* origin
= securityContext().securityOrigin();
291 ASSERT(!origin
->hasSuborigin() || origin
->suboriginName() == name
);
292 origin
->addSuborigin(name
);
293 securityContext().didUpdateSecurityOrigin();
296 DEFINE_TRACE(ExecutionContext
)
299 visitor
->trace(m_pendingExceptions
);
300 visitor
->trace(m_publicURLManager
);
301 HeapSupplementable
<ExecutionContext
>::trace(visitor
);
303 ContextLifecycleNotifier::trace(visitor
);