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