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 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.
25 *
26 */
27
28 #include "config.h"
29 #include "core/dom/ExecutionContext.h"
30
31 #include "core/dom/AddConsoleMessageTask.h"
32 #include "core/dom/ContextLifecycleNotifier.h"
33 #include "core/dom/ExecutionContextTask.h"
34 #include "core/events/ErrorEvent.h"
35 #include "core/events/EventTarget.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 "wtf/MainThread.h"
42
43 namespace blink {
44
45 class ExecutionContext::PendingException : public NoBaseWillBeGarbageCollectedFinalized<ExecutionContext::PendingException> {
46 WTF_MAKE_NONCOPYABLE(PendingException);
47 public:
PendingException(const String & errorMessage,int lineNumber,int columnNumber,int scriptId,const String & sourceURL,PassRefPtrWillBeRawPtr<ScriptCallStack> callStack)48 PendingException(const String& errorMessage, int lineNumber, int columnNumber, int scriptId, const String& sourceURL, PassRefPtrWillBeRawPtr<ScriptCallStack> callStack)
49 : m_errorMessage(errorMessage)
50 , m_lineNumber(lineNumber)
51 , m_columnNumber(columnNumber)
52 , m_scriptId(scriptId)
53 , m_sourceURL(sourceURL)
54 , m_callStack(callStack)
55 {
56 }
trace(Visitor * visitor)57 void trace(Visitor* visitor)
58 {
59 visitor->trace(m_callStack);
60 }
61 String m_errorMessage;
62 int m_lineNumber;
63 int m_columnNumber;
64 int m_scriptId;
65 String m_sourceURL;
66 RefPtrWillBeMember<ScriptCallStack> m_callStack;
67 };
68
ExecutionContext()69 ExecutionContext::ExecutionContext()
70 : m_sandboxFlags(SandboxNone)
71 , m_circularSequentialID(0)
72 , m_inDispatchErrorEvent(false)
73 , m_activeDOMObjectsAreSuspended(false)
74 , m_activeDOMObjectsAreStopped(false)
75 {
76 }
77
~ExecutionContext()78 ExecutionContext::~ExecutionContext()
79 {
80 }
81
hasPendingActivity()82 bool ExecutionContext::hasPendingActivity()
83 {
84 return lifecycleNotifier().hasPendingActivity();
85 }
86
suspendActiveDOMObjects()87 void ExecutionContext::suspendActiveDOMObjects()
88 {
89 lifecycleNotifier().notifySuspendingActiveDOMObjects();
90 m_activeDOMObjectsAreSuspended = true;
91 }
92
resumeActiveDOMObjects()93 void ExecutionContext::resumeActiveDOMObjects()
94 {
95 m_activeDOMObjectsAreSuspended = false;
96 lifecycleNotifier().notifyResumingActiveDOMObjects();
97 }
98
stopActiveDOMObjects()99 void ExecutionContext::stopActiveDOMObjects()
100 {
101 m_activeDOMObjectsAreStopped = true;
102 lifecycleNotifier().notifyStoppingActiveDOMObjects();
103 }
104
activeDOMObjectCount()105 unsigned ExecutionContext::activeDOMObjectCount()
106 {
107 return lifecycleNotifier().activeDOMObjects().size();
108 }
109
suspendScheduledTasks()110 void ExecutionContext::suspendScheduledTasks()
111 {
112 suspendActiveDOMObjects();
113 tasksWereSuspended();
114 }
115
resumeScheduledTasks()116 void ExecutionContext::resumeScheduledTasks()
117 {
118 resumeActiveDOMObjects();
119 tasksWereResumed();
120 }
121
suspendActiveDOMObjectIfNeeded(ActiveDOMObject * object)122 void ExecutionContext::suspendActiveDOMObjectIfNeeded(ActiveDOMObject* object)
123 {
124 ASSERT(lifecycleNotifier().contains(object));
125 // Ensure all ActiveDOMObjects are suspended also newly created ones.
126 if (m_activeDOMObjectsAreSuspended)
127 object->suspend();
128 }
129
shouldSanitizeScriptError(const String & sourceURL,AccessControlStatus corsStatus)130 bool ExecutionContext::shouldSanitizeScriptError(const String& sourceURL, AccessControlStatus corsStatus)
131 {
132 return !(securityOrigin()->canRequest(completeURL(sourceURL)) || corsStatus == SharableCrossOrigin);
133 }
134
reportException(PassRefPtrWillBeRawPtr<ErrorEvent> event,int scriptId,PassRefPtrWillBeRawPtr<ScriptCallStack> callStack,AccessControlStatus corsStatus)135 void ExecutionContext::reportException(PassRefPtrWillBeRawPtr<ErrorEvent> event, int scriptId, PassRefPtrWillBeRawPtr<ScriptCallStack> callStack, AccessControlStatus corsStatus)
136 {
137 RefPtrWillBeRawPtr<ErrorEvent> errorEvent = event;
138 if (m_inDispatchErrorEvent) {
139 if (!m_pendingExceptions)
140 m_pendingExceptions = adoptPtrWillBeNoop(new WillBeHeapVector<OwnPtrWillBeMember<PendingException> >());
141 m_pendingExceptions->append(adoptPtrWillBeNoop(new PendingException(errorEvent->messageForConsole(), errorEvent->lineno(), errorEvent->colno(), scriptId, errorEvent->filename(), callStack)));
142 return;
143 }
144
145 // First report the original exception and only then all the nested ones.
146 if (!dispatchErrorEvent(errorEvent, corsStatus))
147 logExceptionToConsole(errorEvent->messageForConsole(), scriptId, errorEvent->filename(), errorEvent->lineno(), errorEvent->colno(), callStack);
148
149 if (!m_pendingExceptions)
150 return;
151
152 for (size_t i = 0; i < m_pendingExceptions->size(); i++) {
153 PendingException* e = m_pendingExceptions->at(i).get();
154 logExceptionToConsole(e->m_errorMessage, e->m_scriptId, e->m_sourceURL, e->m_lineNumber, e->m_columnNumber, e->m_callStack);
155 }
156 m_pendingExceptions.clear();
157 }
158
dispatchErrorEvent(PassRefPtrWillBeRawPtr<ErrorEvent> event,AccessControlStatus corsStatus)159 bool ExecutionContext::dispatchErrorEvent(PassRefPtrWillBeRawPtr<ErrorEvent> event, AccessControlStatus corsStatus)
160 {
161 EventTarget* target = errorEventTarget();
162 if (!target)
163 return false;
164
165 RefPtrWillBeRawPtr<ErrorEvent> errorEvent = event;
166 if (shouldSanitizeScriptError(errorEvent->filename(), corsStatus))
167 errorEvent = ErrorEvent::createSanitizedError(errorEvent->world());
168
169 ASSERT(!m_inDispatchErrorEvent);
170 m_inDispatchErrorEvent = true;
171 target->dispatchEvent(errorEvent);
172 m_inDispatchErrorEvent = false;
173 return errorEvent->defaultPrevented();
174 }
175
circularSequentialID()176 int ExecutionContext::circularSequentialID()
177 {
178 ++m_circularSequentialID;
179 if (m_circularSequentialID <= 0)
180 m_circularSequentialID = 1;
181 return m_circularSequentialID;
182 }
183
installNewTimeout(PassOwnPtr<ScheduledAction> action,int timeout,bool singleShot)184 int ExecutionContext::installNewTimeout(PassOwnPtr<ScheduledAction> action, int timeout, bool singleShot)
185 {
186 int timeoutID;
187 while (true) {
188 timeoutID = circularSequentialID();
189 if (!m_timeouts.contains(timeoutID))
190 break;
191 }
192 TimeoutMap::AddResult result = m_timeouts.add(timeoutID, DOMTimer::create(this, action, timeout, singleShot, timeoutID));
193 ASSERT(result.isNewEntry);
194 DOMTimer* timer = result.storedValue->value.get();
195
196 timer->suspendIfNeeded();
197
198 return timer->timeoutID();
199 }
200
removeTimeoutByID(int timeoutID)201 void ExecutionContext::removeTimeoutByID(int timeoutID)
202 {
203 if (timeoutID <= 0)
204 return;
205 m_timeouts.remove(timeoutID);
206 }
207
publicURLManager()208 PublicURLManager& ExecutionContext::publicURLManager()
209 {
210 if (!m_publicURLManager)
211 m_publicURLManager = PublicURLManager::create(this);
212 return *m_publicURLManager;
213 }
214
didChangeTimerAlignmentInterval()215 void ExecutionContext::didChangeTimerAlignmentInterval()
216 {
217 for (TimeoutMap::iterator iter = m_timeouts.begin(); iter != m_timeouts.end(); ++iter)
218 iter->value->didChangeAlignmentInterval();
219 }
220
securityOrigin()221 SecurityOrigin* ExecutionContext::securityOrigin()
222 {
223 return securityContext().securityOrigin();
224 }
225
contentSecurityPolicy()226 ContentSecurityPolicy* ExecutionContext::contentSecurityPolicy()
227 {
228 return securityContext().contentSecurityPolicy();
229 }
230
url() const231 const KURL& ExecutionContext::url() const
232 {
233 return virtualURL();
234 }
235
completeURL(const String & url) const236 KURL ExecutionContext::completeURL(const String& url) const
237 {
238 return virtualCompleteURL(url);
239 }
240
createLifecycleNotifier()241 PassOwnPtr<LifecycleNotifier<ExecutionContext> > ExecutionContext::createLifecycleNotifier()
242 {
243 return ContextLifecycleNotifier::create(this);
244 }
245
lifecycleNotifier()246 ContextLifecycleNotifier& ExecutionContext::lifecycleNotifier()
247 {
248 return static_cast<ContextLifecycleNotifier&>(LifecycleContext<ExecutionContext>::lifecycleNotifier());
249 }
250
isIteratingOverObservers() const251 bool ExecutionContext::isIteratingOverObservers() const
252 {
253 return m_lifecycleNotifier && m_lifecycleNotifier->isIteratingOverObservers();
254 }
255
enforceSandboxFlags(SandboxFlags mask)256 void ExecutionContext::enforceSandboxFlags(SandboxFlags mask)
257 {
258 m_sandboxFlags |= mask;
259
260 // The SandboxOrigin is stored redundantly in the security origin.
261 if (isSandboxed(SandboxOrigin) && securityContext().securityOrigin() && !securityContext().securityOrigin()->isUnique()) {
262 securityContext().setSecurityOrigin(SecurityOrigin::createUnique());
263 didUpdateSecurityOrigin();
264 }
265 }
266
trace(Visitor * visitor)267 void ExecutionContext::trace(Visitor* visitor)
268 {
269 #if ENABLE(OILPAN)
270 visitor->trace(m_pendingExceptions);
271 HeapSupplementable<ExecutionContext>::trace(visitor);
272 #endif
273 LifecycleContext<ExecutionContext>::trace(visitor);
274 }
275
276 } // namespace blink
277