Home | History | Annotate | Download | only in dom
      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