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: 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 } 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 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 76 ExecutionContext::~ExecutionContext() 77 { 78 } 79 80 bool ExecutionContext::hasPendingActivity() 81 { 82 return lifecycleNotifier().hasPendingActivity(); 83 } 84 85 void ExecutionContext::suspendActiveDOMObjects() 86 { 87 lifecycleNotifier().notifySuspendingActiveDOMObjects(); 88 m_activeDOMObjectsAreSuspended = true; 89 } 90 91 void ExecutionContext::resumeActiveDOMObjects() 92 { 93 m_activeDOMObjectsAreSuspended = false; 94 lifecycleNotifier().notifyResumingActiveDOMObjects(); 95 } 96 97 void ExecutionContext::stopActiveDOMObjects() 98 { 99 m_activeDOMObjectsAreStopped = true; 100 lifecycleNotifier().notifyStoppingActiveDOMObjects(); 101 } 102 103 unsigned ExecutionContext::activeDOMObjectCount() 104 { 105 return lifecycleNotifier().activeDOMObjects().size(); 106 } 107 108 void ExecutionContext::suspendScheduledTasks() 109 { 110 suspendActiveDOMObjects(); 111 if (m_client) 112 m_client->tasksWereSuspended(); 113 } 114 115 void ExecutionContext::resumeScheduledTasks() 116 { 117 resumeActiveDOMObjects(); 118 if (m_client) 119 m_client->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, 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 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 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 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 193 int ExecutionContext::circularSequentialID() 194 { 195 ++m_circularSequentialID; 196 if (m_circularSequentialID <= 0) 197 m_circularSequentialID = 1; 198 return m_circularSequentialID; 199 } 200 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 218 void ExecutionContext::removeTimeoutByID(int timeoutID) 219 { 220 if (timeoutID <= 0) 221 return; 222 m_timeouts.remove(timeoutID); 223 } 224 225 PublicURLManager& ExecutionContext::publicURLManager() 226 { 227 if (!m_publicURLManager) 228 m_publicURLManager = PublicURLManager::create(this); 229 return *m_publicURLManager; 230 } 231 232 void ExecutionContext::didChangeTimerAlignmentInterval() 233 { 234 for (TimeoutMap::iterator iter = m_timeouts.begin(); iter != m_timeouts.end(); ++iter) 235 iter->value->didChangeAlignmentInterval(); 236 } 237 238 SecurityOrigin* ExecutionContext::securityOrigin() const 239 { 240 RELEASE_ASSERT(m_client); 241 return m_client->securityContext().securityOrigin(); 242 } 243 244 ContentSecurityPolicy* ExecutionContext::contentSecurityPolicy() const 245 { 246 RELEASE_ASSERT(m_client); 247 return m_client->securityContext().contentSecurityPolicy(); 248 } 249 250 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 260 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 271 void ExecutionContext::disableEval(const String& errorMessage) 272 { 273 if (!m_client) 274 return; 275 return m_client->disableEval(errorMessage); 276 } 277 278 LocalDOMWindow* ExecutionContext::executingWindow() const 279 { 280 RELEASE_ASSERT(m_client); 281 return m_client->executingWindow(); 282 } 283 284 String ExecutionContext::userAgent(const KURL& url) const 285 { 286 if (!m_client) 287 return String(); 288 return m_client->userAgent(url); 289 } 290 291 double ExecutionContext::timerAlignmentInterval() const 292 { 293 if (!m_client) 294 return DOMTimer::visiblePageAlignmentInterval(); 295 return m_client->timerAlignmentInterval(); 296 } 297 298 void ExecutionContext::postTask(PassOwnPtr<ExecutionContextTask> task) 299 { 300 if (!m_client) 301 return; 302 m_client->postTask(task); 303 } 304 305 void ExecutionContext::postTask(const Closure& closure) 306 { 307 if (!m_client) 308 return; 309 m_client->postTask(CallClosureTask::create(closure)); 310 } 311 312 PassOwnPtr<LifecycleNotifier<ExecutionContext> > ExecutionContext::createLifecycleNotifier() 313 { 314 return ContextLifecycleNotifier::create(this); 315 } 316 317 ContextLifecycleNotifier& ExecutionContext::lifecycleNotifier() 318 { 319 return static_cast<ContextLifecycleNotifier&>(LifecycleContext<ExecutionContext>::lifecycleNotifier()); 320 } 321 322 bool ExecutionContext::isIteratingOverObservers() const 323 { 324 return m_lifecycleNotifier && m_lifecycleNotifier->isIteratingOverObservers(); 325 } 326 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 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