Move URL from WebCore to WTF
[WebKit-https.git] / Source / WebCore / dom / ScriptExecutionContext.h
1 /*
2  * Copyright (C) 2008-2017 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 #pragma once
29
30 #include "ActiveDOMObject.h"
31 #include "DOMTimer.h"
32 #include "SecurityContext.h"
33 #include "ServiceWorkerTypes.h"
34 #include <JavaScriptCore/ConsoleTypes.h>
35 #include <JavaScriptCore/HandleTypes.h>
36 #include <wtf/CrossThreadTask.h>
37 #include <wtf/Function.h>
38 #include <wtf/HashSet.h>
39 #include <wtf/ObjectIdentifier.h>
40 #include <wtf/text/WTFString.h>
41
42 namespace JSC {
43 class Exception;
44 class ExecState;
45 class JSPromise;
46 class VM;
47 template<typename> class Strong;
48 }
49
50 namespace Inspector {
51 class ConsoleMessage;
52 class ScriptCallStack;
53 }
54
55 namespace PAL {
56 class SessionID;
57 }
58
59 namespace WebCore {
60
61 class CachedScript;
62 class DatabaseContext;
63 class EventQueue;
64 class EventTarget;
65 class MessagePort;
66 class PublicURLManager;
67 class RejectedPromiseTracker;
68 class ResourceRequest;
69 class SecurityOrigin;
70 class SocketProvider;
71
72 #if ENABLE(SERVICE_WORKER)
73 class ServiceWorker;
74 class ServiceWorkerContainer;
75 #endif
76
77 namespace IDBClient {
78 class IDBConnectionProxy;
79 }
80
81 enum ScriptExecutionContextIdentifierType { };
82 using ScriptExecutionContextIdentifier = ObjectIdentifier<ScriptExecutionContextIdentifierType>;
83
84 class ScriptExecutionContext : public SecurityContext {
85 public:
86     ScriptExecutionContext();
87     virtual ~ScriptExecutionContext();
88
89     virtual bool isDocument() const { return false; }
90     virtual bool isWorkerGlobalScope() const { return false; }
91     virtual bool isWorkletGlobalScope() const { return false; }
92
93     virtual bool isContextThread() const { return true; }
94     virtual bool isJSExecutionForbidden() const = 0;
95
96     virtual const URL& url() const = 0;
97     virtual URL completeURL(const String& url) const = 0;
98     virtual PAL::SessionID sessionID() const = 0;
99
100     virtual String userAgent(const URL&) const = 0;
101
102     virtual void disableEval(const String& errorMessage) = 0;
103     virtual void disableWebAssembly(const String& errorMessage) = 0;
104
105 #if ENABLE(INDEXED_DATABASE)
106     virtual IDBClient::IDBConnectionProxy* idbConnectionProxy() = 0;
107 #endif
108     virtual SocketProvider* socketProvider() = 0;
109
110     virtual String resourceRequestIdentifier() const { return String(); };
111
112     bool canIncludeErrorDetails(CachedScript*, const String& sourceURL);
113     void reportException(const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL, JSC::Exception*, RefPtr<Inspector::ScriptCallStack>&&, CachedScript* = nullptr);
114     void reportUnhandledPromiseRejection(JSC::ExecState&, JSC::JSPromise&, RefPtr<Inspector::ScriptCallStack>&&);
115
116     virtual void addConsoleMessage(std::unique_ptr<Inspector::ConsoleMessage>&&) = 0;
117
118     // The following addConsoleMessage functions are deprecated.
119     // Callers should try to create the ConsoleMessage themselves.
120     void addConsoleMessage(MessageSource, MessageLevel, const String& message, const String& sourceURL, unsigned lineNumber, unsigned columnNumber, JSC::ExecState* = nullptr, unsigned long requestIdentifier = 0);
121     virtual void addConsoleMessage(MessageSource, MessageLevel, const String& message, unsigned long requestIdentifier = 0) = 0;
122
123     virtual SecurityOrigin& topOrigin() const = 0;
124     virtual String origin() const = 0;
125
126     virtual bool shouldBypassMainWorldContentSecurityPolicy() const { return false; }
127
128     PublicURLManager& publicURLManager();
129
130     // Active objects are not garbage collected even if inaccessible, e.g. because their activity may result in callbacks being invoked.
131     WEBCORE_EXPORT bool canSuspendActiveDOMObjectsForDocumentSuspension(Vector<ActiveDOMObject*>* unsuspendableObjects = nullptr);
132
133     // Active objects can be asked to suspend even if canSuspendActiveDOMObjectsForDocumentSuspension() returns 'false' -
134     // step-by-step JS debugging is one example.
135     virtual void suspendActiveDOMObjects(ReasonForSuspension);
136     virtual void resumeActiveDOMObjects(ReasonForSuspension);
137     virtual void stopActiveDOMObjects();
138
139     bool activeDOMObjectsAreSuspended() const { return m_activeDOMObjectsAreSuspended; }
140     bool activeDOMObjectsAreStopped() const { return m_activeDOMObjectsAreStopped; }
141
142     // Called from the constructor and destructors of ActiveDOMObject.
143     void didCreateActiveDOMObject(ActiveDOMObject&);
144     void willDestroyActiveDOMObject(ActiveDOMObject&);
145
146     // Called after the construction of an ActiveDOMObject to synchronize suspend state.
147     void suspendActiveDOMObjectIfNeeded(ActiveDOMObject&);
148
149     void didCreateDestructionObserver(ContextDestructionObserver&);
150     void willDestroyDestructionObserver(ContextDestructionObserver&);
151
152     // MessagePort is conceptually a kind of ActiveDOMObject, but it needs to be tracked separately for message dispatch.
153     void processMessageWithMessagePortsSoon();
154     void dispatchMessagePortEvents();
155     void createdMessagePort(MessagePort&);
156     void destroyedMessagePort(MessagePort&);
157
158     virtual void didLoadResourceSynchronously();
159
160     void ref() { refScriptExecutionContext(); }
161     void deref() { derefScriptExecutionContext(); }
162
163     class Task {
164         WTF_MAKE_FAST_ALLOCATED;
165     public:
166         enum CleanupTaskTag { CleanupTask };
167
168         template<typename T, typename = typename std::enable_if<!std::is_base_of<Task, T>::value && std::is_convertible<T, WTF::Function<void (ScriptExecutionContext&)>>::value>::type>
169         Task(T task)
170             : m_task(WTFMove(task))
171             , m_isCleanupTask(false)
172         {
173         }
174
175         Task(WTF::Function<void ()>&& task)
176             : m_task([task = WTFMove(task)](ScriptExecutionContext&) { task(); })
177             , m_isCleanupTask(false)
178         {
179         }
180
181         template<typename T, typename = typename std::enable_if<std::is_convertible<T, WTF::Function<void (ScriptExecutionContext&)>>::value>::type>
182         Task(CleanupTaskTag, T task)
183             : m_task(WTFMove(task))
184             , m_isCleanupTask(true)
185         {
186         }
187
188         void performTask(ScriptExecutionContext& context) { m_task(context); }
189         bool isCleanupTask() const { return m_isCleanupTask; }
190
191     protected:
192         WTF::Function<void (ScriptExecutionContext&)> m_task;
193         bool m_isCleanupTask;
194     };
195
196     virtual void postTask(Task&&) = 0; // Executes the task on context's thread asynchronously.
197
198     template<typename... Arguments>
199     void postCrossThreadTask(Arguments&&... arguments)
200     {
201         postTask([crossThreadTask = createCrossThreadTask(arguments...)](ScriptExecutionContext&) mutable {
202             crossThreadTask.performTask();
203         });
204     }
205
206     // Gets the next id in a circular sequence from 1 to 2^31-1.
207     int circularSequentialID();
208
209     bool addTimeout(int timeoutId, DOMTimer& timer) { return m_timeouts.add(timeoutId, &timer).isNewEntry; }
210     void removeTimeout(int timeoutId) { m_timeouts.remove(timeoutId); }
211     DOMTimer* findTimeout(int timeoutId) { return m_timeouts.get(timeoutId); }
212
213     WEBCORE_EXPORT JSC::VM& vm();
214
215     void adjustMinimumDOMTimerInterval(Seconds oldMinimumTimerInterval);
216     virtual Seconds minimumDOMTimerInterval() const;
217
218     void didChangeTimerAlignmentInterval();
219     virtual Seconds domTimerAlignmentInterval(bool hasReachedMaxNestingLevel) const;
220
221     virtual EventQueue& eventQueue() const = 0;
222     virtual EventTarget* errorEventTarget() = 0;
223
224     DatabaseContext* databaseContext() { return m_databaseContext.get(); }
225     void setDatabaseContext(DatabaseContext*);
226
227 #if ENABLE(WEB_CRYPTO)
228     virtual bool wrapCryptoKey(const Vector<uint8_t>& key, Vector<uint8_t>& wrappedKey) = 0;
229     virtual bool unwrapCryptoKey(const Vector<uint8_t>& wrappedKey, Vector<uint8_t>& key) = 0;
230 #endif
231
232     int timerNestingLevel() const { return m_timerNestingLevel; }
233     void setTimerNestingLevel(int timerNestingLevel) { m_timerNestingLevel = timerNestingLevel; }
234
235     RejectedPromiseTracker& ensureRejectedPromiseTracker()
236     {
237         if (m_rejectedPromiseTracker)
238             return *m_rejectedPromiseTracker.get();
239         return ensureRejectedPromiseTrackerSlow();
240     }
241
242     WEBCORE_EXPORT JSC::ExecState* execState();
243
244     WEBCORE_EXPORT String domainForCachePartition() const;
245     void setDomainForCachePartition(String&& domain) { m_domainForCachePartition = WTFMove(domain); }
246
247     bool hasServiceWorkerScheme();
248 #if ENABLE(SERVICE_WORKER)
249     ServiceWorker* activeServiceWorker() const;
250     void setActiveServiceWorker(RefPtr<ServiceWorker>&&);
251
252     void registerServiceWorker(ServiceWorker&);
253     void unregisterServiceWorker(ServiceWorker&);
254     ServiceWorker* serviceWorker(ServiceWorkerIdentifier identifier) { return m_serviceWorkers.get(identifier); }
255
256     ServiceWorkerContainer* serviceWorkerContainer();
257
258     WEBCORE_EXPORT static bool postTaskTo(const DocumentOrWorkerIdentifier&, WTF::Function<void(ScriptExecutionContext&)>&&);
259 #endif
260     WEBCORE_EXPORT static bool postTaskTo(ScriptExecutionContextIdentifier, Task&&);
261
262     ScriptExecutionContextIdentifier contextIdentifier() const;
263
264 protected:
265     class AddConsoleMessageTask : public Task {
266     public:
267         AddConsoleMessageTask(std::unique_ptr<Inspector::ConsoleMessage>&& consoleMessage)
268             : Task([&consoleMessage](ScriptExecutionContext& context) {
269                 context.addConsoleMessage(WTFMove(consoleMessage));
270             })
271         {
272         }
273
274         AddConsoleMessageTask(MessageSource source, MessageLevel level, const String& message)
275             : Task([source, level, message = message.isolatedCopy()](ScriptExecutionContext& context) {
276                 context.addConsoleMessage(source, level, message);
277             })
278         {
279         }
280     };
281
282     ReasonForSuspension reasonForSuspendingActiveDOMObjects() const { return m_reasonForSuspendingActiveDOMObjects; }
283
284     bool hasPendingActivity() const;
285     void removeFromContextsMap();
286     void removeRejectedPromiseTracker();
287
288 private:
289     // The following addMessage function is deprecated.
290     // Callers should try to create the ConsoleMessage themselves.
291     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;
292     virtual void logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, int columnNumber, RefPtr<Inspector::ScriptCallStack>&&) = 0;
293     bool dispatchErrorEvent(const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL, JSC::Exception*, CachedScript*);
294
295     virtual void refScriptExecutionContext() = 0;
296     virtual void derefScriptExecutionContext() = 0;
297
298     enum class ShouldContinue { No, Yes };
299     void forEachActiveDOMObject(const Function<ShouldContinue(ActiveDOMObject&)>&) const;
300
301     RejectedPromiseTracker& ensureRejectedPromiseTrackerSlow();
302
303     void checkConsistency() const;
304
305     HashSet<MessagePort*> m_messagePorts;
306     HashSet<ContextDestructionObserver*> m_destructionObservers;
307     HashSet<ActiveDOMObject*> m_activeDOMObjects;
308
309     HashMap<int, RefPtr<DOMTimer>> m_timeouts;
310
311     struct PendingException;
312     std::unique_ptr<Vector<std::unique_ptr<PendingException>>> m_pendingExceptions;
313     std::unique_ptr<RejectedPromiseTracker> m_rejectedPromiseTracker;
314
315     ReasonForSuspension m_reasonForSuspendingActiveDOMObjects { static_cast<ReasonForSuspension>(-1) };
316
317     std::unique_ptr<PublicURLManager> m_publicURLManager;
318
319     RefPtr<DatabaseContext> m_databaseContext;
320
321     int m_circularSequentialID { 0 };
322     int m_timerNestingLevel { 0 };
323
324     bool m_activeDOMObjectsAreSuspended { false };
325     bool m_activeDOMObjectsAreStopped { false };
326     bool m_inDispatchErrorEvent { false };
327     mutable bool m_activeDOMObjectAdditionForbidden { false };
328     bool m_willprocessMessageWithMessagePortsSoon { false };
329
330 #if !ASSERT_DISABLED
331     bool m_inScriptExecutionContextDestructor { false };
332 #endif
333
334 #if ENABLE(SERVICE_WORKER)
335     RefPtr<ServiceWorker> m_activeServiceWorker;
336     HashMap<ServiceWorkerIdentifier, ServiceWorker*> m_serviceWorkers;
337 #endif
338
339     String m_domainForCachePartition;
340     mutable ScriptExecutionContextIdentifier m_contextIdentifier;
341 };
342
343 } // namespace WebCore