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 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 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#ifndef ScriptExecutionContext_h
29#define ScriptExecutionContext_h
30
31#include "ActiveDOMObject.h"
32#include "DOMTimer.h"
33#include "ResourceRequest.h"
34#include "SecurityContext.h"
35#include "Supplementable.h"
36#include <runtime/ConsoleTypes.h>
37#include <wtf/HashSet.h>
38
39namespace JSC {
40class ExecState;
41class VM;
42}
43
44namespace Inspector {
45class ScriptCallStack;
46}
47
48namespace WebCore {
49
50class CachedScript;
51class DatabaseContext;
52class EventQueue;
53class EventTarget;
54class MessagePort;
55class PublicURLManager;
56class SecurityOrigin;
57class URL;
58
59class ScriptExecutionContext : public SecurityContext, public Supplementable<ScriptExecutionContext> {
60public:
61 ScriptExecutionContext();
62 virtual ~ScriptExecutionContext();
63
64 virtual bool isDocument() const { return false; }
65 virtual bool isWorkerGlobalScope() const { return false; }
66
67 virtual bool isContextThread() const { return true; }
68 virtual bool isJSExecutionForbidden() const = 0;
69
70 virtual const URL& url() const = 0;
71 virtual URL completeURL(const String& url) const = 0;
72
73 virtual String userAgent(const URL&) const = 0;
74
75 virtual void disableEval(const String& errorMessage) = 0;
76
77 bool sanitizeScriptError(String& errorMessage, int& lineNumber, int& columnNumber, String& sourceURL, CachedScript* = nullptr);
78 void reportException(const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL, RefPtr<Inspector::ScriptCallStack>&&, CachedScript* = nullptr);
79
80 void addConsoleMessage(MessageSource, MessageLevel, const String& message, const String& sourceURL, unsigned lineNumber, unsigned columnNumber, JSC::ExecState* = nullptr, unsigned long requestIdentifier = 0);
81 virtual void addConsoleMessage(MessageSource, MessageLevel, const String& message, unsigned long requestIdentifier = 0) = 0;
82
83 virtual SecurityOrigin* topOrigin() const = 0;
84
85 virtual bool shouldBypassMainWorldContentSecurityPolicy() const { return false; }
86
87 PublicURLManager& publicURLManager();
88
89 // Active objects are not garbage collected even if inaccessible, e.g. because their activity may result in callbacks being invoked.
90 WEBCORE_EXPORT bool canSuspendActiveDOMObjectsForDocumentSuspension(Vector<ActiveDOMObject*>* unsuspendableObjects = nullptr);
91
92 // Active objects can be asked to suspend even if canSuspendActiveDOMObjectsForDocumentSuspension() returns 'false' -
93 // step-by-step JS debugging is one example.
94 virtual void suspendActiveDOMObjects(ActiveDOMObject::ReasonForSuspension);
95 virtual void resumeActiveDOMObjects(ActiveDOMObject::ReasonForSuspension);
96 virtual void stopActiveDOMObjects();
97
98 bool activeDOMObjectsAreSuspended() const { return m_activeDOMObjectsAreSuspended; }
99 bool activeDOMObjectsAreStopped() const { return m_activeDOMObjectsAreStopped; }
100
101 // Called from the constructor and destructors of ActiveDOMObject.
102 void didCreateActiveDOMObject(ActiveDOMObject&);
103 void willDestroyActiveDOMObject(ActiveDOMObject&);
104
105 // Called after the construction of an ActiveDOMObject to synchronize suspend state.
106 void suspendActiveDOMObjectIfNeeded(ActiveDOMObject&);
107
108 void didCreateDestructionObserver(ContextDestructionObserver&);
109 void willDestroyDestructionObserver(ContextDestructionObserver&);
110
111 // MessagePort is conceptually a kind of ActiveDOMObject, but it needs to be tracked separately for message dispatch.
112 void processMessagePortMessagesSoon();
113 void dispatchMessagePortEvents();
114 void createdMessagePort(MessagePort&);
115 void destroyedMessagePort(MessagePort&);
116
117 virtual void didLoadResourceSynchronously(const ResourceRequest&);
118
119 void ref() { refScriptExecutionContext(); }
120 void deref() { derefScriptExecutionContext(); }
121
122 class Task {
123 WTF_MAKE_FAST_ALLOCATED;
124 public:
125 enum CleanupTaskTag { CleanupTask };
126
127 template<typename T, typename = typename std::enable_if<!std::is_base_of<Task, T>::value && std::is_convertible<T, std::function<void (ScriptExecutionContext&)>>::value>::type>
128 Task(T task)
129 : m_task(WTFMove(task))
130 , m_isCleanupTask(false)
131 {
132 }
133
134 Task(std::function<void()> task)
135 : m_task([task](ScriptExecutionContext&) { task(); })
136 , m_isCleanupTask(false)
137 {
138 }
139
140 template<typename T, typename = typename std::enable_if<std::is_convertible<T, std::function<void (ScriptExecutionContext&)>>::value>::type>
141 Task(CleanupTaskTag, T task)
142 : m_task(WTFMove(task))
143 , m_isCleanupTask(true)
144 {
145 }
146
147 Task(Task&& other)
148 : m_task(WTFMove(other.m_task))
149 , m_isCleanupTask(other.m_isCleanupTask)
150 {
151 }
152
153 void performTask(ScriptExecutionContext& context) { m_task(context); }
154 bool isCleanupTask() const { return m_isCleanupTask; }
155
156 protected:
157 std::function<void (ScriptExecutionContext&)> m_task;
158 bool m_isCleanupTask;
159 };
160
161 virtual void postTask(Task) = 0; // Executes the task on context's thread asynchronously.
162
163 // Gets the next id in a circular sequence from 1 to 2^31-1.
164 int circularSequentialID();
165
166 bool addTimeout(int timeoutId, PassRefPtr<DOMTimer> timer) { return m_timeouts.add(timeoutId, timer).isNewEntry; }
167 void removeTimeout(int timeoutId) { m_timeouts.remove(timeoutId); }
168 DOMTimer* findTimeout(int timeoutId) { return m_timeouts.get(timeoutId); }
169
170 WEBCORE_EXPORT JSC::VM& vm();
171
172 // Interval is in seconds.
173 void adjustMinimumTimerInterval(double oldMinimumTimerInterval);
174 virtual double minimumTimerInterval() const;
175
176 void didChangeTimerAlignmentInterval();
177 virtual double timerAlignmentInterval(bool hasReachedMaxNestingLevel) const;
178
179 virtual EventQueue& eventQueue() const = 0;
180
181 void setDatabaseContext(DatabaseContext*);
182
183#if ENABLE(SUBTLE_CRYPTO)
184 virtual bool wrapCryptoKey(const Vector<uint8_t>& key, Vector<uint8_t>& wrappedKey) = 0;
185 virtual bool unwrapCryptoKey(const Vector<uint8_t>& wrappedKey, Vector<uint8_t>& key) = 0;
186#endif
187
188 int timerNestingLevel() const { return m_timerNestingLevel; }
189 void setTimerNestingLevel(int timerNestingLevel) { m_timerNestingLevel = timerNestingLevel; }
190
191protected:
192 class AddConsoleMessageTask : public Task {
193 public:
194 AddConsoleMessageTask(MessageSource source, MessageLevel level, const StringCapture& message)
195 : Task([source, level, message](ScriptExecutionContext& context) {
196 context.addConsoleMessage(source, level, message.string());
197 })
198 {
199 }
200 };
201
202 ActiveDOMObject::ReasonForSuspension reasonForSuspendingActiveDOMObjects() const { return m_reasonForSuspendingActiveDOMObjects; }
203
204 bool hasPendingActivity() const;
205
206private:
207 virtual void addMessage(MessageSource, MessageLevel, const String& message, const String& sourceURL, unsigned lineNumber, unsigned columnNumber, RefPtr<Inspector::ScriptCallStack>&&, JSC::ExecState* = nullptr, unsigned long requestIdentifier = 0) = 0;
208 virtual EventTarget* errorEventTarget() = 0;
209 virtual void logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, int columnNumber, RefPtr<Inspector::ScriptCallStack>&&) = 0;
210 bool dispatchErrorEvent(const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL, CachedScript*);
211
212 virtual void refScriptExecutionContext() = 0;
213 virtual void derefScriptExecutionContext() = 0;
214
215 void checkConsistency() const;
216
217 HashSet<MessagePort*> m_messagePorts;
218 HashSet<ContextDestructionObserver*> m_destructionObservers;
219 HashSet<ActiveDOMObject*> m_activeDOMObjects;
220
221 int m_circularSequentialID;
222 HashMap<int, RefPtr<DOMTimer>> m_timeouts;
223
224 bool m_inDispatchErrorEvent;
225 class PendingException;
226 std::unique_ptr<Vector<std::unique_ptr<PendingException>>> m_pendingExceptions;
227
228 bool m_activeDOMObjectsAreSuspended;
229 ActiveDOMObject::ReasonForSuspension m_reasonForSuspendingActiveDOMObjects;
230 bool m_activeDOMObjectsAreStopped;
231
232 std::unique_ptr<PublicURLManager> m_publicURLManager;
233
234 RefPtr<DatabaseContext> m_databaseContext;
235
236 bool m_activeDOMObjectAdditionForbidden;
237 int m_timerNestingLevel;
238
239#if !ASSERT_DISABLED
240 bool m_inScriptExecutionContextDestructor;
241#endif
242#if !ASSERT_DISABLED || ENABLE(SECURITY_ASSERTIONS)
243 bool m_activeDOMObjectRemovalForbidden;
244#endif
245};
246
247} // namespace WebCore
248
249#endif // ScriptExecutionContext_h
250