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 COMPUTER, 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 COMPUTER, 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 "core/workers/WorkerGlobalScope.h"
31 #include "bindings/core/v8/ExceptionState.h"
32 #include "bindings/core/v8/ScheduledAction.h"
33 #include "bindings/core/v8/ScriptSourceCode.h"
34 #include "bindings/core/v8/ScriptValue.h"
35 #include "core/dom/ActiveDOMObject.h"
36 #include "core/dom/AddConsoleMessageTask.h"
37 #include "core/dom/ContextLifecycleNotifier.h"
38 #include "core/dom/DOMURL.h"
39 #include "core/dom/ExceptionCode.h"
40 #include "core/dom/MessagePort.h"
41 #include "core/events/ErrorEvent.h"
42 #include "core/events/Event.h"
43 #include "core/inspector/ConsoleMessage.h"
44 #include "core/inspector/ConsoleMessageStorage.h"
45 #include "core/inspector/InspectorConsoleInstrumentation.h"
46 #include "core/inspector/ScriptCallStack.h"
47 #include "core/inspector/WorkerInspectorController.h"
48 #include "core/loader/WorkerThreadableLoader.h"
49 #include "core/frame/LocalDOMWindow.h"
50 #include "core/workers/WorkerNavigator.h"
51 #include "core/workers/WorkerClients.h"
52 #include "core/workers/WorkerConsole.h"
53 #include "core/workers/WorkerLocation.h"
54 #include "core/workers/WorkerNavigator.h"
55 #include "core/workers/WorkerReportingProxy.h"
56 #include "core/workers/WorkerScriptLoader.h"
57 #include "core/workers/WorkerThread.h"
58 #include "platform/network/ContentSecurityPolicyParsers.h"
59 #include "platform/weborigin/KURL.h"
60 #include "platform/weborigin/SecurityOrigin.h"
61 #include "public/platform/WebURLRequest.h"
65 class CloseWorkerGlobalScopeTask : public ExecutionContextTask {
67 static PassOwnPtr<CloseWorkerGlobalScopeTask> create()
69 return adoptPtr(new CloseWorkerGlobalScopeTask);
72 virtual void performTask(ExecutionContext *context)
74 WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(context);
75 // Notify parent that this context is closed. Parent is responsible for calling WorkerThread::stop().
76 workerGlobalScope->thread()->workerReportingProxy().workerGlobalScopeClosed();
79 virtual bool isCleanupTask() const { return true; }
82 WorkerGlobalScope::WorkerGlobalScope(const KURL& url, const String& userAgent, WorkerThread* thread, double timeOrigin, const SecurityOrigin* starterOrigin, PassOwnPtrWillBeRawPtr<WorkerClients> workerClients)
84 , m_userAgent(userAgent)
85 , m_script(adoptPtr(new WorkerScriptController(*this)))
87 , m_workerInspectorController(adoptRefWillBeNoop(new WorkerInspectorController(this)))
89 , m_eventQueue(WorkerEventQueue::create(this))
90 , m_workerClients(workerClients)
91 , m_timeOrigin(timeOrigin)
92 , m_messageStorage(ConsoleMessageStorage::createForWorker(this))
94 setSecurityOrigin(SecurityOrigin::create(url));
96 securityOrigin()->transferPrivilegesFrom(*starterOrigin);
98 m_workerClients->reattachThread();
99 m_thread->setWorkerInspectorController(m_workerInspectorController.get());
102 WorkerGlobalScope::~WorkerGlobalScope()
106 void WorkerGlobalScope::applyContentSecurityPolicyFromString(const String& policy, ContentSecurityPolicyHeaderType contentSecurityPolicyType)
108 // FIXME: This doesn't match the CSP2 spec's Worker behavior (see https://w3c.github.io/webappsec/specs/content-security-policy/#processing-model-workers)
109 RefPtr<ContentSecurityPolicy> csp = ContentSecurityPolicy::create();
110 csp->didReceiveHeader(policy, contentSecurityPolicyType, ContentSecurityPolicyHeaderSourceHTTP);
111 csp->bindToExecutionContext(executionContext());
112 setContentSecurityPolicy(csp);
115 ExecutionContext* WorkerGlobalScope::executionContext() const
117 return const_cast<WorkerGlobalScope*>(this);
120 const KURL& WorkerGlobalScope::virtualURL() const
125 KURL WorkerGlobalScope::virtualCompleteURL(const String& url) const
127 return completeURL(url);
130 KURL WorkerGlobalScope::completeURL(const String& url) const
132 // Always return a null URL when passed a null string.
133 // FIXME: Should we change the KURL constructor to have this behavior?
136 // Always use UTF-8 in Workers.
137 return KURL(m_url, url);
140 String WorkerGlobalScope::userAgent(const KURL&) const
145 void WorkerGlobalScope::disableEval(const String& errorMessage)
147 m_script->disableEval(errorMessage);
150 double WorkerGlobalScope::timerAlignmentInterval() const
152 return DOMTimer::visiblePageAlignmentInterval();
155 WorkerLocation* WorkerGlobalScope::location() const
158 m_location = WorkerLocation::create(m_url);
159 return m_location.get();
162 void WorkerGlobalScope::close()
167 // Let current script run to completion but prevent future script evaluations.
168 // After m_closing is set, all the tasks in the queue continue to be fetched but only
169 // tasks with isCleanupTask()==true will be executed.
171 postTask(CloseWorkerGlobalScopeTask::create());
174 WorkerConsole* WorkerGlobalScope::console()
177 m_console = WorkerConsole::create(this);
178 return m_console.get();
181 WorkerNavigator* WorkerGlobalScope::navigator() const
184 m_navigator = WorkerNavigator::create(m_userAgent);
185 return m_navigator.get();
188 void WorkerGlobalScope::postTask(PassOwnPtr<ExecutionContextTask> task)
190 thread()->postTask(task);
193 // FIXME: Called twice, from WorkerThreadShutdownFinishTask and WorkerGlobalScope::dispose.
194 void WorkerGlobalScope::clearInspector()
196 if (!m_workerInspectorController)
198 thread()->setWorkerInspectorController(nullptr);
199 m_workerInspectorController->dispose();
200 m_workerInspectorController.clear();
203 void WorkerGlobalScope::dispose()
205 ASSERT(thread()->isCurrentThread());
207 m_eventQueue->close();
210 // We do not clear the thread field of the
211 // WorkerGlobalScope. Other objects keep the worker global scope
212 // alive because they need its thread field to check that work is
213 // being carried out on the right thread. We therefore cannot clear
214 // the thread field before all references to the worker global
218 void WorkerGlobalScope::didEvaluateWorkerScript()
222 void WorkerGlobalScope::importScripts(const Vector<String>& urls, ExceptionState& exceptionState)
224 ASSERT(contentSecurityPolicy());
225 ASSERT(executionContext());
227 ExecutionContext& executionContext = *this->executionContext();
229 Vector<KURL> completedURLs;
230 for (const String& urlString : urls) {
231 const KURL& url = executionContext.completeURL(urlString);
232 if (!url.isValid()) {
233 exceptionState.throwDOMException(SyntaxError, "The URL '" + urlString + "' is invalid.");
236 if (!contentSecurityPolicy()->allowScriptFromSource(url)) {
237 exceptionState.throwDOMException(NetworkError, "The script at '" + url.elidedString() + "' failed to load.");
240 completedURLs.append(url);
243 for (const KURL& completeURL : completedURLs) {
244 RefPtr<WorkerScriptLoader> scriptLoader(WorkerScriptLoader::create());
245 scriptLoader->setRequestContext(blink::WebURLRequest::RequestContextScript);
246 scriptLoader->loadSynchronously(executionContext, completeURL, AllowCrossOriginRequests);
248 // If the fetching attempt failed, throw a NetworkError exception and abort all these steps.
249 if (scriptLoader->failed()) {
250 exceptionState.throwDOMException(NetworkError, "The script at '" + completeURL.elidedString() + "' failed to load.");
254 InspectorInstrumentation::scriptImported(&executionContext, scriptLoader->identifier(), scriptLoader->script());
256 RefPtrWillBeRawPtr<ErrorEvent> errorEvent = nullptr;
257 m_script->evaluate(ScriptSourceCode(scriptLoader->script(), scriptLoader->responseURL()), &errorEvent);
259 m_script->rethrowExceptionFromImportedScript(errorEvent.release(), exceptionState);
265 EventTarget* WorkerGlobalScope::errorEventTarget()
270 void WorkerGlobalScope::logExceptionToConsole(const String& errorMessage, int, const String& sourceURL, int lineNumber, int columnNumber, PassRefPtrWillBeRawPtr<ScriptCallStack>)
272 thread()->workerReportingProxy().reportException(errorMessage, lineNumber, columnNumber, sourceURL);
275 void WorkerGlobalScope::reportBlockedScriptExecutionToInspector(const String& directiveText)
277 InspectorInstrumentation::scriptExecutionBlockedByCSP(this, directiveText);
280 void WorkerGlobalScope::addConsoleMessage(PassRefPtrWillBeRawPtr<ConsoleMessage> prpConsoleMessage)
282 RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = prpConsoleMessage;
283 if (!isContextThread()) {
284 postTask(AddConsoleMessageTask::create(consoleMessage->source(), consoleMessage->level(), consoleMessage->message()));
287 thread()->workerReportingProxy().reportConsoleMessage(consoleMessage);
288 addMessageToWorkerConsole(consoleMessage.release());
291 void WorkerGlobalScope::addMessageToWorkerConsole(PassRefPtrWillBeRawPtr<ConsoleMessage> consoleMessage)
293 ASSERT(isContextThread());
294 m_messageStorage->reportMessage(consoleMessage);
297 bool WorkerGlobalScope::isContextThread() const
299 return thread()->isCurrentThread();
302 bool WorkerGlobalScope::isJSExecutionForbidden() const
304 return m_script->isExecutionForbidden();
307 bool WorkerGlobalScope::idleNotification()
309 return script()->idleNotification();
312 WorkerEventQueue* WorkerGlobalScope::eventQueue() const
314 return m_eventQueue.get();
317 void WorkerGlobalScope::countFeature(UseCounter::Feature) const
319 // FIXME: How should we count features for shared/service workers?
322 void WorkerGlobalScope::countDeprecation(UseCounter::Feature) const
324 // FIXME: How should we count features for shared/service workers?
327 ConsoleMessageStorage* WorkerGlobalScope::messageStorage()
329 return m_messageStorage.get();
332 void WorkerGlobalScope::trace(Visitor* visitor)
335 visitor->trace(m_console);
336 visitor->trace(m_location);
337 visitor->trace(m_navigator);
338 visitor->trace(m_workerInspectorController);
339 visitor->trace(m_eventQueue);
340 visitor->trace(m_workerClients);
341 visitor->trace(m_messageStorage);
342 HeapSupplementable<WorkerGlobalScope>::trace(visitor);
344 ExecutionContext::trace(visitor);
345 EventTargetWithInlineData::trace(visitor);