• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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