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 { 45 WTF_MAKE_NONCOPYABLE(PendingException); 46 public: 47 PendingException(const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL, PassRefPtr<ScriptCallStack> callStack) 48 : m_errorMessage(errorMessage) 49 , m_lineNumber(lineNumber) 50 , m_columnNumber(columnNumber) 51 , m_sourceURL(sourceURL) 52 , m_callStack(callStack) 53 { 54 } 55 String m_errorMessage; 56 int m_lineNumber; 57 int m_columnNumber; 58 String m_sourceURL; 59 RefPtr<ScriptCallStack> m_callStack; 60 }; 61 62 ExecutionContext::ExecutionContext() 63 : m_client(0) 64 , m_sandboxFlags(SandboxNone) 65 , m_circularSequentialID(0) 66 , m_inDispatchErrorEvent(false) 67 , m_activeDOMObjectsAreSuspended(false) 68 , m_activeDOMObjectsAreStopped(false) 69 { 70 } 71 72 ExecutionContext::~ExecutionContext() 73 { 74 } 75 76 bool ExecutionContext::hasPendingActivity() 77 { 78 return lifecycleNotifier().hasPendingActivity(); 79 } 80 81 void ExecutionContext::suspendActiveDOMObjects() 82 { 83 lifecycleNotifier().notifySuspendingActiveDOMObjects(); 84 m_activeDOMObjectsAreSuspended = true; 85 } 86 87 void ExecutionContext::resumeActiveDOMObjects() 88 { 89 m_activeDOMObjectsAreSuspended = false; 90 lifecycleNotifier().notifyResumingActiveDOMObjects(); 91 } 92 93 void ExecutionContext::stopActiveDOMObjects() 94 { 95 m_activeDOMObjectsAreStopped = true; 96 lifecycleNotifier().notifyStoppingActiveDOMObjects(); 97 } 98 99 void ExecutionContext::suspendScheduledTasks() 100 { 101 suspendActiveDOMObjects(); 102 if (m_client) 103 m_client->tasksWereSuspended(); 104 } 105 106 void ExecutionContext::resumeScheduledTasks() 107 { 108 resumeActiveDOMObjects(); 109 if (m_client) 110 m_client->tasksWereResumed(); 111 } 112 113 void ExecutionContext::suspendActiveDOMObjectIfNeeded(ActiveDOMObject* object) 114 { 115 ASSERT(lifecycleNotifier().contains(object)); 116 // Ensure all ActiveDOMObjects are suspended also newly created ones. 117 if (m_activeDOMObjectsAreSuspended) 118 object->suspend(); 119 } 120 121 bool ExecutionContext::shouldSanitizeScriptError(const String& sourceURL, AccessControlStatus corsStatus) 122 { 123 return !(securityOrigin()->canRequest(completeURL(sourceURL)) || corsStatus == SharableCrossOrigin); 124 } 125 126 void ExecutionContext::reportException(PassRefPtr<ErrorEvent> event, PassRefPtr<ScriptCallStack> callStack, AccessControlStatus corsStatus) 127 { 128 RefPtr<ErrorEvent> errorEvent = event; 129 if (m_inDispatchErrorEvent) { 130 if (!m_pendingExceptions) 131 m_pendingExceptions = adoptPtr(new Vector<OwnPtr<PendingException> >()); 132 m_pendingExceptions->append(adoptPtr(new PendingException(errorEvent->messageForConsole(), errorEvent->lineno(), errorEvent->colno(), errorEvent->filename(), callStack))); 133 return; 134 } 135 136 // First report the original exception and only then all the nested ones. 137 if (!dispatchErrorEvent(errorEvent, corsStatus) && m_client) 138 m_client->logExceptionToConsole(errorEvent->messageForConsole(), errorEvent->filename(), errorEvent->lineno(), errorEvent->colno(), callStack); 139 140 if (!m_pendingExceptions) 141 return; 142 143 for (size_t i = 0; i < m_pendingExceptions->size(); i++) { 144 PendingException* e = m_pendingExceptions->at(i).get(); 145 if (m_client) 146 m_client->logExceptionToConsole(e->m_errorMessage, e->m_sourceURL, e->m_lineNumber, e->m_columnNumber, e->m_callStack); 147 } 148 m_pendingExceptions.clear(); 149 } 150 151 void ExecutionContext::addConsoleMessage(MessageSource source, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber) 152 { 153 if (!m_client) 154 return; 155 m_client->addMessage(source, level, message, sourceURL, lineNumber, 0); 156 } 157 158 void ExecutionContext::addConsoleMessage(MessageSource source, MessageLevel level, const String& message, ScriptState* state) 159 { 160 if (!m_client) 161 return; 162 m_client->addMessage(source, level, message, String(), 0, state); 163 } 164 165 bool ExecutionContext::dispatchErrorEvent(PassRefPtr<ErrorEvent> event, AccessControlStatus corsStatus) 166 { 167 if (!m_client) 168 return false; 169 EventTarget* target = m_client->errorEventTarget(); 170 if (!target) 171 return false; 172 173 RefPtr<ErrorEvent> errorEvent = event; 174 if (shouldSanitizeScriptError(errorEvent->filename(), corsStatus)) 175 errorEvent = ErrorEvent::createSanitizedError(errorEvent->world()); 176 177 ASSERT(!m_inDispatchErrorEvent); 178 m_inDispatchErrorEvent = true; 179 target->dispatchEvent(errorEvent); 180 m_inDispatchErrorEvent = false; 181 return errorEvent->defaultPrevented(); 182 } 183 184 int ExecutionContext::circularSequentialID() 185 { 186 ++m_circularSequentialID; 187 if (m_circularSequentialID <= 0) 188 m_circularSequentialID = 1; 189 return m_circularSequentialID; 190 } 191 192 int ExecutionContext::installNewTimeout(PassOwnPtr<ScheduledAction> action, int timeout, bool singleShot) 193 { 194 int timeoutID; 195 while (true) { 196 timeoutID = circularSequentialID(); 197 if (!m_timeouts.contains(timeoutID)) 198 break; 199 } 200 TimeoutMap::AddResult result = m_timeouts.add(timeoutID, DOMTimer::create(this, action, timeout, singleShot, timeoutID)); 201 ASSERT(result.isNewEntry); 202 DOMTimer* timer = result.iterator->value.get(); 203 204 timer->suspendIfNeeded(); 205 206 return timer->timeoutID(); 207 } 208 209 void ExecutionContext::removeTimeoutByID(int timeoutID) 210 { 211 if (timeoutID <= 0) 212 return; 213 m_timeouts.remove(timeoutID); 214 } 215 216 PublicURLManager& ExecutionContext::publicURLManager() 217 { 218 if (!m_publicURLManager) 219 m_publicURLManager = PublicURLManager::create(this); 220 return *m_publicURLManager; 221 } 222 223 void ExecutionContext::didChangeTimerAlignmentInterval() 224 { 225 for (TimeoutMap::iterator iter = m_timeouts.begin(); iter != m_timeouts.end(); ++iter) 226 iter->value->didChangeAlignmentInterval(); 227 } 228 229 SecurityOrigin* ExecutionContext::securityOrigin() const 230 { 231 RELEASE_ASSERT(m_client); 232 return m_client->securityContext().securityOrigin(); 233 } 234 235 ContentSecurityPolicy* ExecutionContext::contentSecurityPolicy() const 236 { 237 RELEASE_ASSERT(m_client); 238 return m_client->securityContext().contentSecurityPolicy(); 239 } 240 241 const KURL& ExecutionContext::url() const 242 { 243 if (!m_client) { 244 DEFINE_STATIC_LOCAL(KURL, emptyURL, ()); 245 return emptyURL; 246 } 247 248 return m_client->virtualURL(); 249 } 250 251 KURL ExecutionContext::completeURL(const String& url) const 252 { 253 254 if (!m_client) { 255 DEFINE_STATIC_LOCAL(KURL, emptyURL, ()); 256 return emptyURL; 257 } 258 259 return m_client->virtualCompleteURL(url); 260 } 261 262 void ExecutionContext::userEventWasHandled() 263 { 264 if (!m_client) 265 return; 266 m_client->userEventWasHandled(); 267 } 268 269 void ExecutionContext::disableEval(const String& errorMessage) 270 { 271 if (!m_client) 272 return; 273 return m_client->disableEval(errorMessage); 274 } 275 276 DOMWindow* ExecutionContext::executingWindow() const 277 { 278 RELEASE_ASSERT(m_client); 279 return m_client->executingWindow(); 280 } 281 282 String ExecutionContext::userAgent(const KURL& url) const 283 { 284 if (!m_client) 285 return String(); 286 return m_client->userAgent(url); 287 } 288 289 double ExecutionContext::timerAlignmentInterval() const 290 { 291 if (!m_client) 292 return DOMTimer::visiblePageAlignmentInterval(); 293 return m_client->timerAlignmentInterval(); 294 } 295 296 void ExecutionContext::postTask(PassOwnPtr<ExecutionContextTask> task) 297 { 298 if (!m_client) 299 return; 300 m_client->postTask(task); 301 } 302 303 void ExecutionContext::postTask(const Closure& closure) 304 { 305 if (!m_client) 306 return; 307 m_client->postTask(CallClosureTask::create(closure)); 308 } 309 310 PassOwnPtr<LifecycleNotifier<ExecutionContext> > ExecutionContext::createLifecycleNotifier() 311 { 312 return ContextLifecycleNotifier::create(this); 313 } 314 315 ContextLifecycleNotifier& ExecutionContext::lifecycleNotifier() 316 { 317 return static_cast<ContextLifecycleNotifier&>(LifecycleContext<ExecutionContext>::lifecycleNotifier()); 318 } 319 320 bool ExecutionContext::isIteratingOverObservers() const 321 { 322 return m_lifecycleNotifier && m_lifecycleNotifier->isIteratingOverObservers(); 323 } 324 325 void ExecutionContext::enforceSandboxFlags(SandboxFlags mask) 326 { 327 m_sandboxFlags |= mask; 328 329 RELEASE_ASSERT(m_client); 330 // The SandboxOrigin is stored redundantly in the security origin. 331 if (isSandboxed(SandboxOrigin) && m_client->securityContext().securityOrigin() && !m_client->securityContext().securityOrigin()->isUnique()) { 332 m_client->securityContext().setSecurityOrigin(SecurityOrigin::createUnique()); 333 m_client->didUpdateSecurityOrigin(); 334 } 335 } 336 337 } // namespace WebCore 338