2 * Copyright (C) 2008 Apple Inc. All Rights Reserved.
3 * Copyright (C) 2009, 2011 Google Inc. All Rights Reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
29 #include "WorkerGlobalScope.h"
31 #include "ContentSecurityPolicy.h"
33 #include "ExceptionCode.h"
34 #include "IDBConnectionProxy.h"
35 #include "InspectorInstrumentation.h"
36 #include "Performance.h"
37 #include "ScheduledAction.h"
38 #include "ScriptSourceCode.h"
39 #include "SecurityOrigin.h"
40 #include "SecurityOriginPolicy.h"
41 #include "SocketProvider.h"
42 #include "WorkerInspectorController.h"
43 #include "WorkerLoaderProxy.h"
44 #include "WorkerLocation.h"
45 #include "WorkerNavigator.h"
46 #include "WorkerReportingProxy.h"
47 #include "WorkerScriptLoader.h"
48 #include "WorkerThread.h"
49 #include <inspector/ScriptArguments.h>
50 #include <inspector/ScriptCallStack.h>
52 using namespace Inspector;
56 WorkerGlobalScope::WorkerGlobalScope(const URL& url, const String& identifier, const String& userAgent, WorkerThread& thread, bool shouldBypassMainWorldContentSecurityPolicy, Ref<SecurityOrigin>&& topOrigin, MonotonicTime timeOrigin, IDBClient::IDBConnectionProxy* connectionProxy, SocketProvider* socketProvider)
58 , m_identifier(identifier)
59 , m_userAgent(userAgent)
61 , m_script(std::make_unique<WorkerScriptController>(this))
62 , m_inspectorController(std::make_unique<WorkerInspectorController>(*this))
63 , m_shouldBypassMainWorldContentSecurityPolicy(shouldBypassMainWorldContentSecurityPolicy)
65 , m_topOrigin(WTFMove(topOrigin))
66 #if ENABLE(INDEXED_DATABASE)
67 , m_connectionProxy(connectionProxy)
69 #if ENABLE(WEB_SOCKETS)
70 , m_socketProvider(socketProvider)
72 #if ENABLE(WEB_TIMING)
73 , m_performance(Performance::create(*this, timeOrigin))
76 #if !ENABLE(INDEXED_DATABASE)
77 UNUSED_PARAM(connectionProxy);
79 #if !ENABLE(WEB_SOCKETS)
80 UNUSED_PARAM(socketProvider);
82 #if !ENABLE(WEB_TIMING)
83 UNUSED_PARAM(timeOrigin);
86 auto origin = SecurityOrigin::create(url);
87 if (m_topOrigin->hasUniversalAccess())
88 origin->grantUniversalAccess();
89 if (m_topOrigin->needsStorageAccessFromFileURLsQuirk())
90 origin->grantStorageAccessFromFileURLsQuirk();
92 setSecurityOriginPolicy(SecurityOriginPolicy::create(WTFMove(origin)));
93 setContentSecurityPolicy(std::make_unique<ContentSecurityPolicy>(*this));
96 WorkerGlobalScope::~WorkerGlobalScope()
98 ASSERT(currentThread() == thread().threadID());
100 #if ENABLE(WEB_TIMING)
101 m_performance = nullptr;
106 // Notify proxy that we are going away. This can free the WorkerThread object, so do not access it after this.
107 thread().workerReportingProxy().workerGlobalScopeDestroyed();
110 String WorkerGlobalScope::origin() const
112 auto* securityOrigin = this->securityOrigin();
113 return securityOrigin ? securityOrigin->toString() : emptyString();
116 void WorkerGlobalScope::removeAllEventListeners()
118 EventTarget::removeAllEventListeners();
120 #if ENABLE(WEB_TIMING)
121 m_performance->removeAllEventListeners();
125 void WorkerGlobalScope::applyContentSecurityPolicyResponseHeaders(const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders)
127 contentSecurityPolicy()->didReceiveHeaders(contentSecurityPolicyResponseHeaders);
130 URL WorkerGlobalScope::completeURL(const String& url) const
132 // Always return a null URL when passed a null string.
133 // FIXME: Should we change the URL constructor to have this behavior?
136 // Always use UTF-8 in Workers.
137 return URL(m_url, url);
140 String WorkerGlobalScope::userAgent(const URL&) const
145 void WorkerGlobalScope::disableEval(const String& errorMessage)
147 m_script->disableEval(errorMessage);
150 #if ENABLE(WEB_SOCKETS)
152 SocketProvider* WorkerGlobalScope::socketProvider()
154 return m_socketProvider.get();
159 #if ENABLE(INDEXED_DATABASE)
161 IDBClient::IDBConnectionProxy* WorkerGlobalScope::idbConnectionProxy()
163 #if ENABLE(INDEXED_DATABASE_IN_WORKERS)
164 return m_connectionProxy.get();
170 void WorkerGlobalScope::stopIndexedDatabase()
172 #if ENABLE(INDEXED_DATABASE_IN_WORKERS)
173 ASSERT(m_connectionProxy);
174 m_connectionProxy->forgetActivityForCurrentThread();
178 #endif // ENABLE(INDEXED_DATABASE)
180 WorkerLocation& WorkerGlobalScope::location() const
183 m_location = WorkerLocation::create(m_url);
187 void WorkerGlobalScope::close()
192 // Let current script run to completion but prevent future script evaluations.
193 // After m_closing is set, all the tasks in the queue continue to be fetched but only
194 // tasks with isCleanupTask()==true will be executed.
196 postTask({ ScriptExecutionContext::Task::CleanupTask, [] (ScriptExecutionContext& context) {
197 ASSERT_WITH_SECURITY_IMPLICATION(is<WorkerGlobalScope>(context));
198 WorkerGlobalScope& workerGlobalScope = downcast<WorkerGlobalScope>(context);
199 // Notify parent that this context is closed. Parent is responsible for calling WorkerThread::stop().
200 workerGlobalScope.thread().workerReportingProxy().workerGlobalScopeClosed();
204 WorkerNavigator& WorkerGlobalScope::navigator() const
207 m_navigator = WorkerNavigator::create(m_userAgent);
211 void WorkerGlobalScope::postTask(Task&& task)
213 thread().runLoop().postTask(WTFMove(task));
216 int WorkerGlobalScope::setTimeout(std::unique_ptr<ScheduledAction> action, int timeout)
218 return DOMTimer::install(*this, WTFMove(action), Seconds::fromMilliseconds(timeout), true);
221 void WorkerGlobalScope::clearTimeout(int timeoutId)
223 DOMTimer::removeById(*this, timeoutId);
226 int WorkerGlobalScope::setInterval(std::unique_ptr<ScheduledAction> action, int timeout)
228 return DOMTimer::install(*this, WTFMove(action), Seconds::fromMilliseconds(timeout), false);
231 void WorkerGlobalScope::clearInterval(int timeoutId)
233 DOMTimer::removeById(*this, timeoutId);
236 ExceptionOr<void> WorkerGlobalScope::importScripts(const Vector<String>& urls)
238 ASSERT(contentSecurityPolicy());
240 Vector<URL> completedURLs;
241 completedURLs.reserveInitialCapacity(urls.size());
242 for (auto& entry : urls) {
243 URL url = completeURL(entry);
245 return Exception { SYNTAX_ERR };
246 completedURLs.uncheckedAppend(WTFMove(url));
249 for (auto& url : completedURLs) {
250 // FIXME: Convert this to check the isolated world's Content Security Policy once webkit.org/b/104520 is solved.
251 bool shouldBypassMainWorldContentSecurityPolicy = this->shouldBypassMainWorldContentSecurityPolicy();
252 if (!shouldBypassMainWorldContentSecurityPolicy && !contentSecurityPolicy()->allowScriptFromSource(url))
253 return Exception { NETWORK_ERR };
255 auto scriptLoader = WorkerScriptLoader::create();
256 scriptLoader->loadSynchronously(this, url, FetchOptions::Mode::NoCors, shouldBypassMainWorldContentSecurityPolicy ? ContentSecurityPolicyEnforcement::DoNotEnforce : ContentSecurityPolicyEnforcement::EnforceScriptSrcDirective, resourceRequestIdentifier());
258 // If the fetching attempt failed, throw a NETWORK_ERR exception and abort all these steps.
259 if (scriptLoader->failed())
260 return Exception { NETWORK_ERR };
262 InspectorInstrumentation::scriptImported(*this, scriptLoader->identifier(), scriptLoader->script());
264 NakedPtr<JSC::Exception> exception;
265 m_script->evaluate(ScriptSourceCode(scriptLoader->script(), scriptLoader->responseURL()), exception);
267 m_script->setException(exception);
275 EventTarget* WorkerGlobalScope::errorEventTarget()
280 void WorkerGlobalScope::logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, int columnNumber, RefPtr<ScriptCallStack>&&)
282 thread().workerReportingProxy().postExceptionToWorkerObject(errorMessage, lineNumber, columnNumber, sourceURL);
285 void WorkerGlobalScope::addConsoleMessage(std::unique_ptr<Inspector::ConsoleMessage>&& message)
287 if (!isContextThread()) {
288 postTask(AddConsoleMessageTask(message->source(), message->level(), message->message()));
292 InspectorInstrumentation::addMessageToConsole(*this, WTFMove(message));
295 void WorkerGlobalScope::addConsoleMessage(MessageSource source, MessageLevel level, const String& message, unsigned long requestIdentifier)
297 addMessage(source, level, message, { }, 0, 0, nullptr, nullptr, requestIdentifier);
300 void WorkerGlobalScope::addMessage(MessageSource source, MessageLevel level, const String& messageText, const String& sourceURL, unsigned lineNumber, unsigned columnNumber, RefPtr<ScriptCallStack>&& callStack, JSC::ExecState* state, unsigned long requestIdentifier)
302 if (!isContextThread()) {
303 postTask(AddConsoleMessageTask(source, level, messageText));
307 std::unique_ptr<Inspector::ConsoleMessage> message;
309 message = std::make_unique<Inspector::ConsoleMessage>(source, MessageType::Log, level, messageText, callStack.releaseNonNull(), requestIdentifier);
311 message = std::make_unique<Inspector::ConsoleMessage>(source, MessageType::Log, level, messageText, sourceURL, lineNumber, columnNumber, state, requestIdentifier);
312 InspectorInstrumentation::addMessageToConsole(*this, WTFMove(message));
315 bool WorkerGlobalScope::isContextThread() const
317 return currentThread() == thread().threadID();
320 bool WorkerGlobalScope::isJSExecutionForbidden() const
322 return m_script->isExecutionForbidden();
325 WorkerEventQueue& WorkerGlobalScope::eventQueue() const
330 #if ENABLE(SUBTLE_CRYPTO)
332 bool WorkerGlobalScope::wrapCryptoKey(const Vector<uint8_t>& key, Vector<uint8_t>& wrappedKey)
336 m_thread.workerLoaderProxy().postTaskToLoader([&result, &key, &wrappedKey, &done, workerGlobalScope = this](ScriptExecutionContext& context) {
337 result = context.wrapCryptoKey(key, wrappedKey);
339 workerGlobalScope->postTask([](ScriptExecutionContext& context) {
340 ASSERT_UNUSED(context, context.isWorkerGlobalScope());
344 auto waitResult = MessageQueueMessageReceived;
345 while (!done && waitResult != MessageQueueTerminated)
346 waitResult = m_thread.runLoop().runInMode(this, WorkerRunLoop::defaultMode());
351 bool WorkerGlobalScope::unwrapCryptoKey(const Vector<uint8_t>& wrappedKey, Vector<uint8_t>& key)
353 bool result = false, done = false;
354 m_thread.workerLoaderProxy().postTaskToLoader([&result, &wrappedKey, &key, &done, workerGlobalScope = this](ScriptExecutionContext& context) {
355 result = context.unwrapCryptoKey(wrappedKey, key);
357 workerGlobalScope->postTask([](ScriptExecutionContext& context) {
358 ASSERT_UNUSED(context, context.isWorkerGlobalScope());
362 auto waitResult = MessageQueueMessageReceived;
363 while (!done && waitResult != MessageQueueTerminated)
364 waitResult = m_thread.runLoop().runInMode(this, WorkerRunLoop::defaultMode());
369 #endif // ENABLE(SUBTLE_CRYPTO)
371 Crypto& WorkerGlobalScope::crypto()
374 m_crypto = Crypto::create(*this);
378 #if ENABLE(WEB_TIMING)
380 Performance& WorkerGlobalScope::performance() const
382 return *m_performance;
387 } // namespace WebCore