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, 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));
95 m_workerClients->reattachThread();
96 m_thread->setWorkerInspectorController(m_workerInspectorController.get());
99 WorkerGlobalScope::~WorkerGlobalScope()
103 void WorkerGlobalScope::applyContentSecurityPolicyFromString(const String& policy, ContentSecurityPolicyHeaderType contentSecurityPolicyType)
105 // FIXME: This doesn't match the CSP2 spec's Worker behavior (see https://w3c.github.io/webappsec/specs/content-security-policy/#processing-model-workers)
106 RefPtr<ContentSecurityPolicy> csp = ContentSecurityPolicy::create();
107 csp->didReceiveHeader(policy, contentSecurityPolicyType, ContentSecurityPolicyHeaderSourceHTTP);
108 csp->bindToExecutionContext(executionContext());
109 setContentSecurityPolicy(csp);
112 ExecutionContext* WorkerGlobalScope::executionContext() const
114 return const_cast<WorkerGlobalScope*>(this);
117 const KURL& WorkerGlobalScope::virtualURL() const
122 KURL WorkerGlobalScope::virtualCompleteURL(const String& url) const
124 return completeURL(url);
127 KURL WorkerGlobalScope::completeURL(const String& url) const
129 // Always return a null URL when passed a null string.
130 // FIXME: Should we change the KURL constructor to have this behavior?
133 // Always use UTF-8 in Workers.
134 return KURL(m_url, url);
137 String WorkerGlobalScope::userAgent(const KURL&) const
142 void WorkerGlobalScope::disableEval(const String& errorMessage)
144 m_script->disableEval(errorMessage);
147 double WorkerGlobalScope::timerAlignmentInterval() const
149 return DOMTimer::visiblePageAlignmentInterval();
152 WorkerLocation* WorkerGlobalScope::location() const
155 m_location = WorkerLocation::create(m_url);
156 return m_location.get();
159 void WorkerGlobalScope::close()
164 // Let current script run to completion but prevent future script evaluations.
165 // After m_closing is set, all the tasks in the queue continue to be fetched but only
166 // tasks with isCleanupTask()==true will be executed.
168 postTask(CloseWorkerGlobalScopeTask::create());
171 WorkerConsole* WorkerGlobalScope::console()
174 m_console = WorkerConsole::create(this);
175 return m_console.get();
178 WorkerNavigator* WorkerGlobalScope::navigator() const
181 m_navigator = WorkerNavigator::create(m_userAgent);
182 return m_navigator.get();
185 void WorkerGlobalScope::postTask(PassOwnPtr<ExecutionContextTask> task)
187 thread()->postTask(task);
190 // FIXME: Called twice, from WorkerThreadShutdownFinishTask and WorkerGlobalScope::dispose.
191 void WorkerGlobalScope::clearInspector()
193 if (!m_workerInspectorController)
195 thread()->setWorkerInspectorController(nullptr);
196 m_workerInspectorController->dispose();
197 m_workerInspectorController.clear();
200 void WorkerGlobalScope::dispose()
202 ASSERT(thread()->isCurrentThread());
204 m_eventQueue->close();
207 // We do not clear the thread field of the
208 // WorkerGlobalScope. Other objects keep the worker global scope
209 // alive because they need its thread field to check that work is
210 // being carried out on the right thread. We therefore cannot clear
211 // the thread field before all references to the worker global
215 void WorkerGlobalScope::importScripts(const Vector<String>& urls, ExceptionState& exceptionState)
217 ASSERT(contentSecurityPolicy());
218 ASSERT(executionContext());
220 ExecutionContext& executionContext = *this->executionContext();
222 Vector<String>::const_iterator urlsEnd = urls.end();
223 Vector<KURL> completedURLs;
224 for (Vector<String>::const_iterator it = urls.begin(); it != urlsEnd; ++it) {
225 const KURL& url = executionContext.completeURL(*it);
226 if (!url.isValid()) {
227 exceptionState.throwDOMException(SyntaxError, "The URL '" + *it + "' is invalid.");
230 if (!contentSecurityPolicy()->allowScriptFromSource(url)) {
231 exceptionState.throwDOMException(NetworkError, "The script at '" + url.elidedString() + "' failed to load.");
234 completedURLs.append(url);
236 Vector<KURL>::const_iterator end = completedURLs.end();
238 for (Vector<KURL>::const_iterator it = completedURLs.begin(); it != end; ++it) {
239 RefPtr<WorkerScriptLoader> scriptLoader(WorkerScriptLoader::create());
240 scriptLoader->setRequestContext(blink::WebURLRequest::RequestContextScript);
241 scriptLoader->loadSynchronously(executionContext, *it, AllowCrossOriginRequests);
243 // If the fetching attempt failed, throw a NetworkError exception and abort all these steps.
244 if (scriptLoader->failed()) {
245 exceptionState.throwDOMException(NetworkError, "The script at '" + it->elidedString() + "' failed to load.");
249 InspectorInstrumentation::scriptImported(&executionContext, scriptLoader->identifier(), scriptLoader->script());
251 RefPtrWillBeRawPtr<ErrorEvent> errorEvent = nullptr;
252 m_script->evaluate(ScriptSourceCode(scriptLoader->script(), scriptLoader->responseURL()), &errorEvent);
254 m_script->rethrowExceptionFromImportedScript(errorEvent.release(), exceptionState);
260 EventTarget* WorkerGlobalScope::errorEventTarget()
265 void WorkerGlobalScope::logExceptionToConsole(const String& errorMessage, int, const String& sourceURL, int lineNumber, int columnNumber, PassRefPtrWillBeRawPtr<ScriptCallStack>)
267 thread()->workerReportingProxy().reportException(errorMessage, lineNumber, columnNumber, sourceURL);
270 void WorkerGlobalScope::reportBlockedScriptExecutionToInspector(const String& directiveText)
272 InspectorInstrumentation::scriptExecutionBlockedByCSP(this, directiveText);
275 void WorkerGlobalScope::addConsoleMessage(PassRefPtrWillBeRawPtr<ConsoleMessage> prpConsoleMessage)
277 RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = prpConsoleMessage;
278 if (!isContextThread()) {
279 postTask(AddConsoleMessageTask::create(consoleMessage->source(), consoleMessage->level(), consoleMessage->message()));
282 thread()->workerReportingProxy().reportConsoleMessage(consoleMessage);
283 addMessageToWorkerConsole(consoleMessage.release());
286 void WorkerGlobalScope::addMessageToWorkerConsole(PassRefPtrWillBeRawPtr<ConsoleMessage> consoleMessage)
288 ASSERT(isContextThread());
289 m_messageStorage->reportMessage(consoleMessage);
292 bool WorkerGlobalScope::isContextThread() const
294 return thread()->isCurrentThread();
297 bool WorkerGlobalScope::isJSExecutionForbidden() const
299 return m_script->isExecutionForbidden();
302 bool WorkerGlobalScope::idleNotification()
304 return script()->idleNotification();
307 WorkerEventQueue* WorkerGlobalScope::eventQueue() const
309 return m_eventQueue.get();
312 void WorkerGlobalScope::countFeature(UseCounter::Feature) const
314 // FIXME: How should we count features for shared/service workers?
317 void WorkerGlobalScope::countDeprecation(UseCounter::Feature) const
319 // FIXME: How should we count features for shared/service workers?
322 ConsoleMessageStorage* WorkerGlobalScope::messageStorage()
324 return m_messageStorage.get();
327 void WorkerGlobalScope::trace(Visitor* visitor)
330 visitor->trace(m_console);
331 visitor->trace(m_location);
332 visitor->trace(m_navigator);
333 visitor->trace(m_workerInspectorController);
334 visitor->trace(m_eventQueue);
335 visitor->trace(m_workerClients);
336 visitor->trace(m_messageStorage);
337 HeapSupplementable<WorkerGlobalScope>::trace(visitor);
339 ExecutionContext::trace(visitor);
340 EventTargetWithInlineData::trace(visitor);