/* * Copyright (C) 2008, 2009, 2010, 2011, 2013, 2014, 2015, 2016 Apple Inc. All Rights Reserved. * Copyright (C) 2012 Google Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #pragma once #include "ActiveDOMObject.h" #include "DOMTimer.h" #include "SecurityContext.h" #include "Supplementable.h" #include #include #include #include #include namespace JSC { class Exception; class ExecState; class VM; template class Strong; } namespace Inspector { class ScriptCallStack; } namespace WebCore { class CachedScript; class DatabaseContext; class EventQueue; class EventTarget; class MessagePort; class PublicURLManager; class ResourceRequest; class SecurityOrigin; class SocketProvider; class URL; namespace IDBClient { class IDBConnectionProxy; } class ScriptExecutionContext : public SecurityContext { public: ScriptExecutionContext(); virtual ~ScriptExecutionContext(); virtual bool isDocument() const { return false; } virtual bool isWorkerGlobalScope() const { return false; } virtual bool isContextThread() const { return true; } virtual bool isJSExecutionForbidden() const = 0; virtual const URL& url() const = 0; virtual URL completeURL(const String& url) const = 0; virtual String userAgent(const URL&) const = 0; virtual void disableEval(const String& errorMessage) = 0; #if ENABLE(INDEXED_DATABASE) virtual IDBClient::IDBConnectionProxy* idbConnectionProxy() = 0; #endif #if ENABLE(WEB_SOCKETS) virtual SocketProvider* socketProvider() = 0; #endif virtual String resourceRequestIdentifier() const { return String(); }; bool sanitizeScriptError(String& errorMessage, int& lineNumber, int& columnNumber, String& sourceURL, JSC::Strong& error, CachedScript* = nullptr); void reportException(const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL, JSC::Exception*, RefPtr&&, CachedScript* = nullptr); void addConsoleMessage(MessageSource, MessageLevel, const String& message, const String& sourceURL, unsigned lineNumber, unsigned columnNumber, JSC::ExecState* = nullptr, unsigned long requestIdentifier = 0); virtual void addConsoleMessage(MessageSource, MessageLevel, const String& message, unsigned long requestIdentifier = 0) = 0; virtual SecurityOrigin& topOrigin() const = 0; virtual bool shouldBypassMainWorldContentSecurityPolicy() const { return false; } PublicURLManager& publicURLManager(); // Active objects are not garbage collected even if inaccessible, e.g. because their activity may result in callbacks being invoked. WEBCORE_EXPORT bool canSuspendActiveDOMObjectsForDocumentSuspension(Vector* unsuspendableObjects = nullptr); // Active objects can be asked to suspend even if canSuspendActiveDOMObjectsForDocumentSuspension() returns 'false' - // step-by-step JS debugging is one example. virtual void suspendActiveDOMObjects(ActiveDOMObject::ReasonForSuspension); virtual void resumeActiveDOMObjects(ActiveDOMObject::ReasonForSuspension); virtual void stopActiveDOMObjects(); bool activeDOMObjectsAreSuspended() const { return m_activeDOMObjectsAreSuspended; } bool activeDOMObjectsAreStopped() const { return m_activeDOMObjectsAreStopped; } // Called from the constructor and destructors of ActiveDOMObject. void didCreateActiveDOMObject(ActiveDOMObject&); void willDestroyActiveDOMObject(ActiveDOMObject&); // Called after the construction of an ActiveDOMObject to synchronize suspend state. void suspendActiveDOMObjectIfNeeded(ActiveDOMObject&); void didCreateDestructionObserver(ContextDestructionObserver&); void willDestroyDestructionObserver(ContextDestructionObserver&); // MessagePort is conceptually a kind of ActiveDOMObject, but it needs to be tracked separately for message dispatch. void processMessagePortMessagesSoon(); void dispatchMessagePortEvents(); void createdMessagePort(MessagePort&); void destroyedMessagePort(MessagePort&); virtual void didLoadResourceSynchronously(); void ref() { refScriptExecutionContext(); } void deref() { derefScriptExecutionContext(); } class Task { WTF_MAKE_FAST_ALLOCATED; public: enum CleanupTaskTag { CleanupTask }; template::value && std::is_convertible>::value>::type> Task(T task) : m_task(WTFMove(task)) , m_isCleanupTask(false) { } Task(WTF::Function&& task) : m_task([task = WTFMove(task)](ScriptExecutionContext&) { task(); }) , m_isCleanupTask(false) { } template>::value>::type> Task(CleanupTaskTag, T task) : m_task(WTFMove(task)) , m_isCleanupTask(true) { } void performTask(ScriptExecutionContext& context) { m_task(context); } bool isCleanupTask() const { return m_isCleanupTask; } protected: WTF::Function m_task; bool m_isCleanupTask; }; virtual void postTask(Task&&) = 0; // Executes the task on context's thread asynchronously. template void postCrossThreadTask(Arguments&&... arguments) { postTask([crossThreadTask = createCrossThreadTask(arguments...)](ScriptExecutionContext&) mutable { crossThreadTask.performTask(); }); } // Gets the next id in a circular sequence from 1 to 2^31-1. int circularSequentialID(); bool addTimeout(int timeoutId, DOMTimer& timer) { return m_timeouts.add(timeoutId, &timer).isNewEntry; } void removeTimeout(int timeoutId) { m_timeouts.remove(timeoutId); } DOMTimer* findTimeout(int timeoutId) { return m_timeouts.get(timeoutId); } WEBCORE_EXPORT JSC::VM& vm(); // Interval is in seconds. void adjustMinimumTimerInterval(std::chrono::milliseconds oldMinimumTimerInterval); virtual std::chrono::milliseconds minimumTimerInterval() const; void didChangeTimerAlignmentInterval(); virtual std::chrono::milliseconds timerAlignmentInterval(bool hasReachedMaxNestingLevel) const; virtual EventQueue& eventQueue() const = 0; DatabaseContext* databaseContext() { return m_databaseContext.get(); } void setDatabaseContext(DatabaseContext*); #if ENABLE(SUBTLE_CRYPTO) virtual bool wrapCryptoKey(const Vector& key, Vector& wrappedKey) = 0; virtual bool unwrapCryptoKey(const Vector& wrappedKey, Vector& key) = 0; #endif int timerNestingLevel() const { return m_timerNestingLevel; } void setTimerNestingLevel(int timerNestingLevel) { m_timerNestingLevel = timerNestingLevel; } JSC::ExecState* execState(); protected: class AddConsoleMessageTask : public Task { public: AddConsoleMessageTask(MessageSource source, MessageLevel level, const String& message) : Task([source, level, message = message.isolatedCopy()](ScriptExecutionContext& context) { context.addConsoleMessage(source, level, message); }) { } }; ActiveDOMObject::ReasonForSuspension reasonForSuspendingActiveDOMObjects() const { return m_reasonForSuspendingActiveDOMObjects; } bool hasPendingActivity() const; private: virtual void addMessage(MessageSource, MessageLevel, const String& message, const String& sourceURL, unsigned lineNumber, unsigned columnNumber, RefPtr&&, JSC::ExecState* = nullptr, unsigned long requestIdentifier = 0) = 0; virtual EventTarget* errorEventTarget() = 0; virtual void logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, int columnNumber, RefPtr&&) = 0; bool dispatchErrorEvent(const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL, JSC::Exception*, CachedScript*); virtual void refScriptExecutionContext() = 0; virtual void derefScriptExecutionContext() = 0; void checkConsistency() const; HashSet m_messagePorts; HashSet m_destructionObservers; HashSet m_activeDOMObjects; int m_circularSequentialID { 0 }; HashMap> m_timeouts; bool m_inDispatchErrorEvent { false }; struct PendingException; std::unique_ptr>> m_pendingExceptions; bool m_activeDOMObjectsAreSuspended { false }; ActiveDOMObject::ReasonForSuspension m_reasonForSuspendingActiveDOMObjects { static_cast(-1) }; bool m_activeDOMObjectsAreStopped { false }; std::unique_ptr m_publicURLManager; RefPtr m_databaseContext; bool m_activeDOMObjectAdditionForbidden { false }; bool m_willProcessMessagePortMessagesSoon { false }; int m_timerNestingLevel { 0 }; #if !ASSERT_DISABLED bool m_inScriptExecutionContextDestructor { false }; #endif #if !ASSERT_DISABLED || ENABLE(SECURITY_ASSERTIONS) bool m_activeDOMObjectRemovalForbidden { false }; #endif }; } // namespace WebCore