forked from WebKit/WebKit
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ScriptExecutionContext.h
429 lines (330 loc) · 16.7 KB
/
ScriptExecutionContext.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
/*
* Copyright (C) 2008-2017 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 "CrossOriginMode.h"
#include "DOMTimer.h"
#include "ScriptExecutionContextIdentifier.h"
#include "SecurityContext.h"
#include "ServiceWorkerIdentifier.h"
#include "Settings.h"
#include "StorageBlockingPolicy.h"
#include <JavaScriptCore/ConsoleTypes.h>
#include <JavaScriptCore/HandleTypes.h>
#include <pal/SessionID.h>
#include <wtf/CheckedRef.h>
#include <wtf/CrossThreadTask.h>
#include <wtf/Function.h>
#include <wtf/HashSet.h>
#include <wtf/ObjectIdentifier.h>
#include <wtf/URL.h>
#include <wtf/WeakPtr.h>
#include <wtf/text/WTFString.h>
namespace JSC {
class CallFrame;
class Exception;
class JSPromise;
class VM;
enum class ScriptExecutionStatus;
}
namespace Inspector {
class ConsoleMessage;
class ScriptCallStack;
}
namespace WebCore {
class EventLoop;
class CachedScript;
class CSSFontSelector;
class CSSValuePool;
class DatabaseContext;
class DeferredPromise;
class EventQueue;
class EventLoopTaskGroup;
class EventTarget;
class FontLoadRequest;
class MessagePort;
class NotificationClient;
class PublicURLManager;
class RejectedPromiseTracker;
class RTCDataChannelRemoteHandlerConnection;
class ResourceRequest;
class SocketProvider;
class WebCoreOpaqueRoot;
enum class LoadedFromOpaqueSource : bool;
enum class TaskSource : uint8_t;
#if ENABLE(NOTIFICATIONS)
class NotificationClient;
#endif
#if ENABLE(SERVICE_WORKER)
class ServiceWorker;
class ServiceWorkerContainer;
#endif
namespace IDBClient {
class IDBConnectionProxy;
}
class ScriptExecutionContext : public SecurityContext, public CanMakeCheckedPtr, public TimerAlignment {
public:
explicit ScriptExecutionContext(ScriptExecutionContextIdentifier = { });
virtual ~ScriptExecutionContext();
virtual bool isDocument() const { return false; }
virtual bool isWorkerGlobalScope() const { return false; }
virtual bool isServiceWorkerGlobalScope() const { return false; }
virtual bool isWorkletGlobalScope() const { return false; }
virtual bool isContextThread() const { return true; }
virtual bool isJSExecutionForbidden() const = 0;
virtual EventLoopTaskGroup& eventLoop() = 0;
virtual const URL& url() const = 0;
enum class ForceUTF8 : bool { No, Yes };
virtual URL completeURL(const String& url, ForceUTF8 = ForceUTF8::No) const = 0;
virtual String userAgent(const URL&) const = 0;
virtual const Settings::Values& settingsValues() const = 0;
virtual NotificationClient* notificationClient() { return nullptr; }
virtual std::optional<PAL::SessionID> sessionID() const { return std::nullopt; }
virtual void disableEval(const String& errorMessage) = 0;
virtual void disableWebAssembly(const String& errorMessage) = 0;
virtual IDBClient::IDBConnectionProxy* idbConnectionProxy() = 0;
virtual SocketProvider* socketProvider() = 0;
virtual std::optional<uint64_t> noiseInjectionHashSalt() const = 0;
virtual RefPtr<RTCDataChannelRemoteHandlerConnection> createRTCDataChannelRemoteHandlerConnection();
virtual String resourceRequestIdentifier() const { return String(); };
bool canIncludeErrorDetails(CachedScript*, const String& sourceURL, bool = false);
void reportException(const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL, JSC::Exception*, RefPtr<Inspector::ScriptCallStack>&&, CachedScript* = nullptr, bool = false);
void reportUnhandledPromiseRejection(JSC::JSGlobalObject&, JSC::JSPromise&, RefPtr<Inspector::ScriptCallStack>&&);
virtual void addConsoleMessage(std::unique_ptr<Inspector::ConsoleMessage>&&) = 0;
// The following addConsoleMessage functions are deprecated.
// Callers should try to create the ConsoleMessage themselves.
void addConsoleMessage(MessageSource, MessageLevel, const String& message, const String& sourceURL, unsigned lineNumber, unsigned columnNumber, JSC::JSGlobalObject* = 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();
virtual void suspendActiveDOMObjects(ReasonForSuspension);
virtual void resumeActiveDOMObjects(ReasonForSuspension);
virtual void stopActiveDOMObjects();
bool activeDOMObjectsAreSuspended() const { return m_activeDOMObjectsAreSuspended; }
bool activeDOMObjectsAreStopped() const { return m_activeDOMObjectsAreStopped; }
JSC::ScriptExecutionStatus jscScriptExecutionStatus() const;
URL currentSourceURL() const;
// 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 processMessageWithMessagePortsSoon(CompletionHandler<void()>&&);
void createdMessagePort(MessagePort&);
void destroyedMessagePort(MessagePort&);
virtual void didLoadResourceSynchronously(const URL&);
virtual CSSFontSelector* cssFontSelector() { return nullptr; }
virtual CSSValuePool& cssValuePool();
virtual std::unique_ptr<FontLoadRequest> fontLoadRequest(const String& url, bool isSVG, bool isInitiatingElementInUserAgentShadowTree, LoadedFromOpaqueSource);
virtual void beginLoadingFontSoon(FontLoadRequest&) { }
WEBCORE_EXPORT static void setCrossOriginMode(CrossOriginMode);
static CrossOriginMode crossOriginMode();
void ref() { refScriptExecutionContext(); }
void deref() { derefScriptExecutionContext(); }
class Task {
WTF_MAKE_FAST_ALLOCATED;
public:
enum CleanupTaskTag { CleanupTask };
template<typename T, typename = typename std::enable_if<!std::is_base_of<Task, T>::value && std::is_convertible<T, Function<void(ScriptExecutionContext&)>>::value>::type>
Task(T task)
: m_task(WTFMove(task))
, m_isCleanupTask(false)
{
}
Task(Function<void()>&& task)
: m_task([task = WTFMove(task)](ScriptExecutionContext&) { task(); })
, m_isCleanupTask(false)
{
}
template<typename T, typename = typename std::enable_if<std::is_convertible<T, Function<void(ScriptExecutionContext&)>>::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:
Function<void(ScriptExecutionContext&)> m_task;
bool m_isCleanupTask;
};
virtual void postTask(Task&&) = 0; // Executes the task on context's thread asynchronously.
template<typename... Arguments>
void postCrossThreadTask(Arguments&&... arguments)
{
postTask([crossThreadTask = createCrossThreadTask(arguments...)](ScriptExecutionContext&) mutable {
crossThreadTask.performTask();
});
}
void postTaskToResponsibleDocument(Function<void(Document&)>&&);
// 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; }
RefPtr<DOMTimer> takeTimeout(int timeoutId) { return m_timeouts.take(timeoutId); }
DOMTimer* findTimeout(int timeoutId) { return m_timeouts.get(timeoutId); }
virtual JSC::VM& vm() = 0;
void adjustMinimumDOMTimerInterval(Seconds oldMinimumTimerInterval);
virtual Seconds minimumDOMTimerInterval() const;
void didChangeTimerAlignmentInterval();
virtual Seconds domTimerAlignmentInterval(bool hasReachedMaxNestingLevel) const;
// TimerAlignment
WEBCORE_EXPORT std::optional<MonotonicTime> alignedFireTime(bool hasReachedMaxNestingLevel, MonotonicTime fireTime) const final;
virtual EventTarget* errorEventTarget() = 0;
DatabaseContext* databaseContext() { return m_databaseContext.get(); }
void setDatabaseContext(DatabaseContext*);
#if ENABLE(WEB_CRYPTO)
// These two methods are used when CryptoKeys are serialized into IndexedDB. As a side effect, it is also
// used for things that utilize the same structure clone algorithm, for example, message passing between
// worker and document.
virtual bool wrapCryptoKey(const Vector<uint8_t>& key, Vector<uint8_t>& wrappedKey) = 0;
virtual bool unwrapCryptoKey(const Vector<uint8_t>& wrappedKey, Vector<uint8_t>& key) = 0;
#endif
int timerNestingLevel() const { return m_timerNestingLevel; }
void setTimerNestingLevel(int timerNestingLevel) { m_timerNestingLevel = timerNestingLevel; }
RejectedPromiseTracker* rejectedPromiseTracker()
{
return m_rejectedPromiseTracker.get();
}
RejectedPromiseTracker* ensureRejectedPromiseTracker()
{
if (m_rejectedPromiseTracker)
return m_rejectedPromiseTracker.get();
return ensureRejectedPromiseTrackerSlow();
}
WEBCORE_EXPORT JSC::JSGlobalObject* globalObject() const;
WEBCORE_EXPORT String domainForCachePartition() const;
void setDomainForCachePartition(String&& domain) { m_domainForCachePartition = WTFMove(domain); }
bool allowsMediaDevices() const;
#if ENABLE(SERVICE_WORKER)
ServiceWorker* activeServiceWorker() const;
void setActiveServiceWorker(RefPtr<ServiceWorker>&&);
void registerServiceWorker(ServiceWorker&);
void unregisterServiceWorker(ServiceWorker&);
ServiceWorker* serviceWorker(ServiceWorkerIdentifier identifier) { return m_serviceWorkers.get(identifier); }
ServiceWorkerContainer* serviceWorkerContainer();
ServiceWorkerContainer* ensureServiceWorkerContainer();
virtual void updateServiceWorkerClientData() { ASSERT_NOT_REACHED(); }
#endif
WEBCORE_EXPORT static bool postTaskTo(ScriptExecutionContextIdentifier, Task&&);
WEBCORE_EXPORT static bool postTaskForModeToWorkerOrWorklet(ScriptExecutionContextIdentifier, Task&&, const String&);
WEBCORE_EXPORT static bool ensureOnContextThread(ScriptExecutionContextIdentifier, Task&&);
ScriptExecutionContextIdentifier identifier() const { return m_identifier; }
bool hasLoggedAuthenticatedEncryptionWarning() const { return m_hasLoggedAuthenticatedEncryptionWarning; }
void setHasLoggedAuthenticatedEncryptionWarning(bool value) { m_hasLoggedAuthenticatedEncryptionWarning = value; }
void setStorageBlockingPolicy(StorageBlockingPolicy policy) { m_storageBlockingPolicy = policy; }
enum class ResourceType : uint8_t {
ApplicationCache,
Cookies,
Geolocation,
IndexedDB,
LocalStorage,
Plugin,
SessionStorage,
StorageManager,
WebSQL
};
enum class HasResourceAccess : uint8_t { No, Yes, DefaultForThirdParty };
WEBCORE_EXPORT HasResourceAccess canAccessResource(ResourceType) const;
enum NotificationCallbackIdentifierType { };
using NotificationCallbackIdentifier = AtomicObjectIdentifier<NotificationCallbackIdentifierType>;
WEBCORE_EXPORT NotificationCallbackIdentifier addNotificationCallback(CompletionHandler<void()>&&);
WEBCORE_EXPORT CompletionHandler<void()> takeNotificationCallback(NotificationCallbackIdentifier);
void addDeferredPromise(Ref<DeferredPromise>&&);
RefPtr<DeferredPromise> takeDeferredPromise(DeferredPromise*);
protected:
class AddConsoleMessageTask : public Task {
public:
AddConsoleMessageTask(std::unique_ptr<Inspector::ConsoleMessage>&& consoleMessage)
: Task([&consoleMessage](ScriptExecutionContext& context) {
context.addConsoleMessage(WTFMove(consoleMessage));
})
{
}
AddConsoleMessageTask(MessageSource source, MessageLevel level, const String& message)
: Task([source, level, message = message.isolatedCopy()](ScriptExecutionContext& context) {
context.addConsoleMessage(source, level, message);
})
{
}
};
ReasonForSuspension reasonForSuspendingActiveDOMObjects() const { return m_reasonForSuspendingActiveDOMObjects; }
bool hasPendingActivity() const;
WEBCORE_EXPORT void addToContextsMap();
void removeFromContextsMap();
void removeRejectedPromiseTracker();
void regenerateIdentifier();
private:
// The following addMessage function is deprecated.
// Callers should try to create the ConsoleMessage themselves.
virtual void addMessage(MessageSource, MessageLevel, const String& message, const String& sourceURL, unsigned lineNumber, unsigned columnNumber, RefPtr<Inspector::ScriptCallStack>&&, JSC::JSGlobalObject* = nullptr, unsigned long requestIdentifier = 0) = 0;
virtual void logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, int columnNumber, RefPtr<Inspector::ScriptCallStack>&&) = 0;
bool dispatchErrorEvent(const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL, JSC::Exception*, CachedScript*, bool);
virtual void refScriptExecutionContext() = 0;
virtual void derefScriptExecutionContext() = 0;
void dispatchMessagePortEvents();
enum class ShouldContinue : bool { No, Yes };
void forEachActiveDOMObject(const Function<ShouldContinue(ActiveDOMObject&)>&) const;
RejectedPromiseTracker* ensureRejectedPromiseTrackerSlow();
void checkConsistency() const;
HashSet<MessagePort*> m_messagePorts;
HashSet<ContextDestructionObserver*> m_destructionObservers;
HashSet<ActiveDOMObject*> m_activeDOMObjects;
HashMap<int, RefPtr<DOMTimer>> m_timeouts;
struct PendingException;
std::unique_ptr<Vector<std::unique_ptr<PendingException>>> m_pendingExceptions;
std::unique_ptr<RejectedPromiseTracker> m_rejectedPromiseTracker;
std::unique_ptr<PublicURLManager> m_publicURLManager;
RefPtr<DatabaseContext> m_databaseContext;
int m_circularSequentialID { 0 };
int m_timerNestingLevel { 0 };
Vector<CompletionHandler<void()>> m_processMessageWithMessagePortsSoonHandlers;
#if ASSERT_ENABLED
bool m_inScriptExecutionContextDestructor { false };
#endif
#if ENABLE(SERVICE_WORKER)
RefPtr<ServiceWorker> m_activeServiceWorker;
HashMap<ServiceWorkerIdentifier, ServiceWorker*> m_serviceWorkers;
#endif
String m_domainForCachePartition;
mutable ScriptExecutionContextIdentifier m_identifier;
HashMap<NotificationCallbackIdentifier, CompletionHandler<void()>> m_notificationCallbacks;
HashSet<Ref<DeferredPromise>> m_deferredPromises;
StorageBlockingPolicy m_storageBlockingPolicy { StorageBlockingPolicy::AllowAll };
ReasonForSuspension m_reasonForSuspendingActiveDOMObjects { static_cast<ReasonForSuspension>(-1) };
bool m_activeDOMObjectsAreSuspended { false };
bool m_activeDOMObjectsAreStopped { false };
bool m_inDispatchErrorEvent { false };
mutable bool m_activeDOMObjectAdditionForbidden { false };
bool m_willprocessMessageWithMessagePortsSoon { false };
bool m_hasLoggedAuthenticatedEncryptionWarning { false };
};
WebCoreOpaqueRoot root(ScriptExecutionContext*);
} // namespace WebCore