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/EventTarget.h"
35 #include "core/html/PublicURLManager.h"
36 #include "core/inspector/InspectorInstrumentation.h"
37 #include "core/inspector/ScriptCallStack.h"
38 #include "core/workers/WorkerGlobalScope.h"
39 #include "core/workers/WorkerThread.h"
40 #include "wtf/MainThread.h"
41
42 namespace WebCore {
43
44 class ExecutionContext::PendingException : public NoBaseWillBeGarbageCollectedFinalized<ExecutionContext::PendingException> {
45 WTF_MAKE_NONCOPYABLE(PendingException);
46 public:
PendingException(const String & errorMessage,int lineNumber,int columnNumber,const String & sourceURL,PassRefPtrWillBeRawPtr<ScriptCallStack> callStack)47 PendingException(const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL, PassRefPtrWillBeRawPtr<ScriptCallStack> callStack)
48 : m_errorMessage(errorMessage)
49 , m_lineNumber(lineNumber)
50 , m_columnNumber(columnNumber)
51 , m_sourceURL(sourceURL)
52 , m_callStack(callStack)
53 {
54 }
trace(Visitor * visitor)55 void trace(Visitor* visitor)
56 {
57 visitor->trace(m_callStack);
58 }
59 String m_errorMessage;
60 int m_lineNumber;
61 int m_columnNumber;
62 String m_sourceURL;
63 RefPtrWillBeMember<ScriptCallStack> m_callStack;
64 };
65
ExecutionContext()66 ExecutionContext::ExecutionContext()
67 : m_client(0)
68 , m_sandboxFlags(SandboxNone)
69 , m_circularSequentialID(0)
70 , m_inDispatchErrorEvent(false)
71 , m_activeDOMObjectsAreSuspended(false)
72 , m_activeDOMObjectsAreStopped(false)
73 {
74 }
75
~ExecutionContext()76 ExecutionContext::~ExecutionContext()
77 {
78 }
79
hasPendingActivity()80 bool ExecutionContext::hasPendingActivity()
81 {
82 return lifecycleNotifier().hasPendingActivity();
83 }
84
suspendActiveDOMObjects()85 void ExecutionContext::suspendActiveDOMObjects()
86 {
87 lifecycleNotifier().notifySuspendingActiveDOMObjects();
88 m_activeDOMObjectsAreSuspended = true;
89 }
90
resumeActiveDOMObjects()91 void ExecutionContext::resumeActiveDOMObjects()
92 {
93 m_activeDOMObjectsAreSuspended = false;
94 lifecycleNotifier().notifyResumingActiveDOMObjects();
95 }
96
stopActiveDOMObjects()97 void ExecutionContext::stopActiveDOMObjects()
98 {
99 m_activeDOMObjectsAreStopped = true;
100 lifecycleNotifier().notifyStoppingActiveDOMObjects();
101 }
102
activeDOMObjectCount()103 unsigned ExecutionContext::activeDOMObjectCount()
104 {
105 return lifecycleNotifier().activeDOMObjects().size();
106 }
107
suspendScheduledTasks()108 void ExecutionContext::suspendScheduledTasks()
109 {
110 suspendActiveDOMObjects();
111 if (m_client)
112 m_client->tasksWereSuspended();
113 }
114
resumeScheduledTasks()115 void ExecutionContext::resumeScheduledTasks()
116 {
117 resumeActiveDOMObjects();
118 if (m_client)
119 m_client->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,PassRefPtrWillBeRawPtr<ScriptCallStack> callStack,AccessControlStatus corsStatus)135 void ExecutionContext::reportException(PassRefPtrWillBeRawPtr<ErrorEvent> event, 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(), 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) && m_client)
147 m_client->logExceptionToConsole(errorEvent->messageForConsole(), 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 if (m_client)
155 m_client->logExceptionToConsole(e->m_errorMessage, e->m_sourceURL, e->m_lineNumber, e->m_columnNumber, e->m_callStack);
156 }
157 m_pendingExceptions.clear();
158 }
159
addConsoleMessage(MessageSource source,MessageLevel level,const String & message,const String & sourceURL,unsigned lineNumber)160 void ExecutionContext::addConsoleMessage(MessageSource source, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber)
161 {
162 if (!m_client)
163 return;
164 m_client->addMessage(source, level, message, sourceURL, lineNumber, 0);
165 }
166
addConsoleMessage(MessageSource source,MessageLevel level,const String & message,ScriptState * scriptState)167 void ExecutionContext::addConsoleMessage(MessageSource source, MessageLevel level, const String& message, ScriptState* scriptState)
168 {
169 if (!m_client)
170 return;
171 m_client->addMessage(source, level, message, String(), 0, scriptState);
172 }
173
dispatchErrorEvent(PassRefPtrWillBeRawPtr<ErrorEvent> event,AccessControlStatus corsStatus)174 bool ExecutionContext::dispatchErrorEvent(PassRefPtrWillBeRawPtr<ErrorEvent> event, AccessControlStatus corsStatus)
175 {
176 if (!m_client)
177 return false;
178 EventTarget* target = m_client->errorEventTarget();
179 if (!target)
180 return false;
181
182 RefPtrWillBeRawPtr<ErrorEvent> errorEvent = event;
183 if (shouldSanitizeScriptError(errorEvent->filename(), corsStatus))
184 errorEvent = ErrorEvent::createSanitizedError(errorEvent->world());
185
186 ASSERT(!m_inDispatchErrorEvent);
187 m_inDispatchErrorEvent = true;
188 target->dispatchEvent(errorEvent);
189 m_inDispatchErrorEvent = false;
190 return errorEvent->defaultPrevented();
191 }
192
circularSequentialID()193 int ExecutionContext::circularSequentialID()
194 {
195 ++m_circularSequentialID;
196 if (m_circularSequentialID <= 0)
197 m_circularSequentialID = 1;
198 return m_circularSequentialID;
199 }
200
installNewTimeout(PassOwnPtr<ScheduledAction> action,int timeout,bool singleShot)201 int ExecutionContext::installNewTimeout(PassOwnPtr<ScheduledAction> action, int timeout, bool singleShot)
202 {
203 int timeoutID;
204 while (true) {
205 timeoutID = circularSequentialID();
206 if (!m_timeouts.contains(timeoutID))
207 break;
208 }
209 TimeoutMap::AddResult result = m_timeouts.add(timeoutID, DOMTimer::create(this, action, timeout, singleShot, timeoutID));
210 ASSERT(result.isNewEntry);
211 DOMTimer* timer = result.storedValue->value.get();
212
213 timer->suspendIfNeeded();
214
215 return timer->timeoutID();
216 }
217
removeTimeoutByID(int timeoutID)218 void ExecutionContext::removeTimeoutByID(int timeoutID)
219 {
220 if (timeoutID <= 0)
221 return;
222 m_timeouts.remove(timeoutID);
223 }
224
publicURLManager()225 PublicURLManager& ExecutionContext::publicURLManager()
226 {
227 if (!m_publicURLManager)
228 m_publicURLManager = PublicURLManager::create(this);
229 return *m_publicURLManager;
230 }
231
didChangeTimerAlignmentInterval()232 void ExecutionContext::didChangeTimerAlignmentInterval()
233 {
234 for (TimeoutMap::iterator iter = m_timeouts.begin(); iter != m_timeouts.end(); ++iter)
235 iter->value->didChangeAlignmentInterval();
236 }
237
securityOrigin() const238 SecurityOrigin* ExecutionContext::securityOrigin() const
239 {
240 RELEASE_ASSERT(m_client);
241 return m_client->securityContext().securityOrigin();
242 }
243
contentSecurityPolicy() const244 ContentSecurityPolicy* ExecutionContext::contentSecurityPolicy() const
245 {
246 RELEASE_ASSERT(m_client);
247 return m_client->securityContext().contentSecurityPolicy();
248 }
249
url() const250 const KURL& ExecutionContext::url() const
251 {
252 if (!m_client) {
253 DEFINE_STATIC_LOCAL(KURL, emptyURL, ());
254 return emptyURL;
255 }
256
257 return virtualURL();
258 }
259
completeURL(const String & url) const260 KURL ExecutionContext::completeURL(const String& url) const
261 {
262
263 if (!m_client) {
264 DEFINE_STATIC_LOCAL(KURL, emptyURL, ());
265 return emptyURL;
266 }
267
268 return virtualCompleteURL(url);
269 }
270
disableEval(const String & errorMessage)271 void ExecutionContext::disableEval(const String& errorMessage)
272 {
273 if (!m_client)
274 return;
275 return m_client->disableEval(errorMessage);
276 }
277
executingWindow() const278 LocalDOMWindow* ExecutionContext::executingWindow() const
279 {
280 RELEASE_ASSERT(m_client);
281 return m_client->executingWindow();
282 }
283
userAgent(const KURL & url) const284 String ExecutionContext::userAgent(const KURL& url) const
285 {
286 if (!m_client)
287 return String();
288 return m_client->userAgent(url);
289 }
290
timerAlignmentInterval() const291 double ExecutionContext::timerAlignmentInterval() const
292 {
293 if (!m_client)
294 return DOMTimer::visiblePageAlignmentInterval();
295 return m_client->timerAlignmentInterval();
296 }
297
postTask(PassOwnPtr<ExecutionContextTask> task)298 void ExecutionContext::postTask(PassOwnPtr<ExecutionContextTask> task)
299 {
300 if (!m_client)
301 return;
302 m_client->postTask(task);
303 }
304
postTask(const Closure & closure)305 void ExecutionContext::postTask(const Closure& closure)
306 {
307 if (!m_client)
308 return;
309 m_client->postTask(CallClosureTask::create(closure));
310 }
311
createLifecycleNotifier()312 PassOwnPtr<LifecycleNotifier<ExecutionContext> > ExecutionContext::createLifecycleNotifier()
313 {
314 return ContextLifecycleNotifier::create(this);
315 }
316
lifecycleNotifier()317 ContextLifecycleNotifier& ExecutionContext::lifecycleNotifier()
318 {
319 return static_cast<ContextLifecycleNotifier&>(LifecycleContext<ExecutionContext>::lifecycleNotifier());
320 }
321
isIteratingOverObservers() const322 bool ExecutionContext::isIteratingOverObservers() const
323 {
324 return m_lifecycleNotifier && m_lifecycleNotifier->isIteratingOverObservers();
325 }
326
enforceSandboxFlags(SandboxFlags mask)327 void ExecutionContext::enforceSandboxFlags(SandboxFlags mask)
328 {
329 m_sandboxFlags |= mask;
330
331 RELEASE_ASSERT(m_client);
332 // The SandboxOrigin is stored redundantly in the security origin.
333 if (isSandboxed(SandboxOrigin) && m_client->securityContext().securityOrigin() && !m_client->securityContext().securityOrigin()->isUnique()) {
334 m_client->securityContext().setSecurityOrigin(SecurityOrigin::createUnique());
335 m_client->didUpdateSecurityOrigin();
336 }
337 }
338
trace(Visitor * visitor)339 void ExecutionContext::trace(Visitor* visitor)
340 {
341 #if ENABLE(OILPAN)
342 visitor->trace(m_pendingExceptions);
343 #endif
344 Supplementable<WebCore::ExecutionContext>::trace(visitor);
345 }
346
347 } // namespace WebCore
348