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: 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 } 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 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 78 ExecutionContext::~ExecutionContext() 79 { 80 } 81 82 bool ExecutionContext::hasPendingActivity() 83 { 84 return lifecycleNotifier().hasPendingActivity(); 85 } 86 87 void ExecutionContext::suspendActiveDOMObjects() 88 { 89 lifecycleNotifier().notifySuspendingActiveDOMObjects(); 90 m_activeDOMObjectsAreSuspended = true; 91 } 92 93 void ExecutionContext::resumeActiveDOMObjects() 94 { 95 m_activeDOMObjectsAreSuspended = false; 96 lifecycleNotifier().notifyResumingActiveDOMObjects(); 97 } 98 99 void ExecutionContext::stopActiveDOMObjects() 100 { 101 m_activeDOMObjectsAreStopped = true; 102 lifecycleNotifier().notifyStoppingActiveDOMObjects(); 103 } 104 105 unsigned ExecutionContext::activeDOMObjectCount() 106 { 107 return lifecycleNotifier().activeDOMObjects().size(); 108 } 109 110 void ExecutionContext::suspendScheduledTasks() 111 { 112 suspendActiveDOMObjects(); 113 tasksWereSuspended(); 114 } 115 116 void ExecutionContext::resumeScheduledTasks() 117 { 118 resumeActiveDOMObjects(); 119 tasksWereResumed(); 120 } 121 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 130 bool ExecutionContext::shouldSanitizeScriptError(const String& sourceURL, AccessControlStatus corsStatus) 131 { 132 return !(securityOrigin()->canRequest(completeURL(sourceURL)) || corsStatus == SharableCrossOrigin); 133 } 134 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 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 176 int ExecutionContext::circularSequentialID() 177 { 178 ++m_circularSequentialID; 179 if (m_circularSequentialID <= 0) 180 m_circularSequentialID = 1; 181 return m_circularSequentialID; 182 } 183 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 201 void ExecutionContext::removeTimeoutByID(int timeoutID) 202 { 203 if (timeoutID <= 0) 204 return; 205 m_timeouts.remove(timeoutID); 206 } 207 208 PublicURLManager& ExecutionContext::publicURLManager() 209 { 210 if (!m_publicURLManager) 211 m_publicURLManager = PublicURLManager::create(this); 212 return *m_publicURLManager; 213 } 214 215 void ExecutionContext::didChangeTimerAlignmentInterval() 216 { 217 for (TimeoutMap::iterator iter = m_timeouts.begin(); iter != m_timeouts.end(); ++iter) 218 iter->value->didChangeAlignmentInterval(); 219 } 220 221 SecurityOrigin* ExecutionContext::securityOrigin() 222 { 223 return securityContext().securityOrigin(); 224 } 225 226 ContentSecurityPolicy* ExecutionContext::contentSecurityPolicy() 227 { 228 return securityContext().contentSecurityPolicy(); 229 } 230 231 const KURL& ExecutionContext::url() const 232 { 233 return virtualURL(); 234 } 235 236 KURL ExecutionContext::completeURL(const String& url) const 237 { 238 return virtualCompleteURL(url); 239 } 240 241 PassOwnPtr<LifecycleNotifier<ExecutionContext> > ExecutionContext::createLifecycleNotifier() 242 { 243 return ContextLifecycleNotifier::create(this); 244 } 245 246 ContextLifecycleNotifier& ExecutionContext::lifecycleNotifier() 247 { 248 return static_cast<ContextLifecycleNotifier&>(LifecycleContext<ExecutionContext>::lifecycleNotifier()); 249 } 250 251 bool ExecutionContext::isIteratingOverObservers() const 252 { 253 return m_lifecycleNotifier && m_lifecycleNotifier->isIteratingOverObservers(); 254 } 255 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 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