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/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