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/v8/ExceptionState.h"
32 #include "bindings/v8/ScheduledAction.h"
33 #include "bindings/v8/ScriptSourceCode.h"
34 #include "bindings/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/InspectorConsoleInstrumentation.h"
44 #include "core/inspector/ScriptCallStack.h"
45 #include "core/inspector/WorkerInspectorController.h"
46 #include "core/loader/WorkerThreadableLoader.h"
47 #include "core/frame/DOMWindow.h"
48 #include "core/workers/WorkerNavigator.h"
49 #include "core/workers/WorkerClients.h"
50 #include "core/workers/WorkerLocation.h"
51 #include "core/workers/WorkerReportingProxy.h"
52 #include "core/workers/WorkerScriptLoader.h"
53 #include "core/workers/WorkerThread.h"
54 #include "platform/network/ContentSecurityPolicyParsers.h"
55 #include "platform/weborigin/KURL.h"
56 #include "platform/weborigin/SecurityOrigin.h"
60 class CloseWorkerGlobalScopeTask : public ExecutionContextTask {
62 static PassOwnPtr<CloseWorkerGlobalScopeTask> create()
64 return adoptPtr(new CloseWorkerGlobalScopeTask);
67 virtual void performTask(ExecutionContext *context)
69 WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(context);
70 // Notify parent that this context is closed. Parent is responsible for calling WorkerThread::stop().
71 workerGlobalScope->thread()->workerReportingProxy().workerGlobalScopeClosed();
74 virtual bool isCleanupTask() const { return true; }
77 WorkerGlobalScope::WorkerGlobalScope(const KURL& url, const String& userAgent, WorkerThread* thread, double timeOrigin, PassOwnPtrWillBeRawPtr<WorkerClients> workerClients)
79 , m_userAgent(userAgent)
80 , m_script(adoptPtr(new WorkerScriptController(*this)))
82 , m_workerInspectorController(adoptPtr(new WorkerInspectorController(this)))
84 , m_eventQueue(WorkerEventQueue::create(this))
85 , m_workerClients(workerClients)
86 , m_timeOrigin(timeOrigin)
87 , m_terminationObserver(0)
89 ScriptWrappable::init(this);
91 setSecurityOrigin(SecurityOrigin::create(url));
92 m_workerClients->reattachThread();
95 WorkerGlobalScope::~WorkerGlobalScope()
99 void WorkerGlobalScope::applyContentSecurityPolicyFromString(const String& policy, ContentSecurityPolicyHeaderType contentSecurityPolicyType)
101 setContentSecurityPolicy(ContentSecurityPolicy::create(this));
102 contentSecurityPolicy()->didReceiveHeader(policy, contentSecurityPolicyType, ContentSecurityPolicyHeaderSourceHTTP);
105 ExecutionContext* WorkerGlobalScope::executionContext() const
107 return const_cast<WorkerGlobalScope*>(this);
110 const KURL& WorkerGlobalScope::virtualURL() const
115 KURL WorkerGlobalScope::virtualCompleteURL(const String& url) const
117 return completeURL(url);
120 KURL WorkerGlobalScope::completeURL(const String& url) const
122 // Always return a null URL when passed a null string.
123 // FIXME: Should we change the KURL constructor to have this behavior?
126 // Always use UTF-8 in Workers.
127 return KURL(m_url, url);
130 String WorkerGlobalScope::userAgent(const KURL&) const
135 void WorkerGlobalScope::disableEval(const String& errorMessage)
137 m_script->disableEval(errorMessage);
140 double WorkerGlobalScope::timerAlignmentInterval() const
142 return DOMTimer::visiblePageAlignmentInterval();
145 WorkerLocation* WorkerGlobalScope::location() const
148 m_location = WorkerLocation::create(m_url);
149 return m_location.get();
152 void WorkerGlobalScope::close()
157 // Let current script run to completion but prevent future script evaluations.
158 // After m_closing is set, all the tasks in the queue continue to be fetched but only
159 // tasks with isCleanupTask()==true will be executed.
161 postTask(CloseWorkerGlobalScopeTask::create());
164 WorkerConsole* WorkerGlobalScope::console()
167 m_console = WorkerConsole::create(this);
168 return m_console.get();
171 WorkerNavigator* WorkerGlobalScope::navigator() const
174 m_navigator = WorkerNavigator::create(m_userAgent);
175 return m_navigator.get();
178 void WorkerGlobalScope::postTask(PassOwnPtr<ExecutionContextTask> task)
180 thread()->runLoop().postTask(task);
183 void WorkerGlobalScope::clearInspector()
185 m_workerInspectorController.clear();
188 void WorkerGlobalScope::registerTerminationObserver(TerminationObserver* observer)
190 ASSERT(!m_terminationObserver);
192 m_terminationObserver = observer;
195 void WorkerGlobalScope::unregisterTerminationObserver(TerminationObserver* observer)
198 ASSERT(m_terminationObserver == observer);
199 m_terminationObserver = 0;
202 void WorkerGlobalScope::wasRequestedToTerminate()
204 if (m_terminationObserver)
205 m_terminationObserver->wasRequestedToTerminate();
208 void WorkerGlobalScope::dispose()
210 ASSERT(thread()->isCurrentThread());
216 // We do not clear the thread field of the
217 // WorkerGlobalScope. Other objects keep the worker global scope
218 // alive because they need its thread field to check that work is
219 // being carried out on the right thread. We therefore cannot clear
220 // the thread field before all references to the worker global
224 void WorkerGlobalScope::importScripts(const Vector<String>& urls, ExceptionState& exceptionState)
226 ASSERT(contentSecurityPolicy());
227 ASSERT(executionContext());
229 ExecutionContext& executionContext = *this->executionContext();
231 Vector<String>::const_iterator urlsEnd = urls.end();
232 Vector<KURL> completedURLs;
233 for (Vector<String>::const_iterator it = urls.begin(); it != urlsEnd; ++it) {
234 const KURL& url = executionContext.completeURL(*it);
235 if (!url.isValid()) {
236 exceptionState.throwDOMException(SyntaxError, "The URL '" + *it + "' is invalid.");
239 if (!contentSecurityPolicy()->allowScriptFromSource(url)) {
240 exceptionState.throwDOMException(NetworkError, "The script at '" + url.elidedString() + "' failed to load.");
243 completedURLs.append(url);
245 Vector<KURL>::const_iterator end = completedURLs.end();
247 for (Vector<KURL>::const_iterator it = completedURLs.begin(); it != end; ++it) {
248 RefPtr<WorkerScriptLoader> scriptLoader(WorkerScriptLoader::create());
249 scriptLoader->setTargetType(ResourceRequest::TargetIsScript);
250 scriptLoader->loadSynchronously(executionContext, *it, AllowCrossOriginRequests);
252 // If the fetching attempt failed, throw a NetworkError exception and abort all these steps.
253 if (scriptLoader->failed()) {
254 exceptionState.throwDOMException(NetworkError, "The script at '" + it->elidedString() + "' failed to load.");
258 InspectorInstrumentation::scriptImported(&executionContext, scriptLoader->identifier(), scriptLoader->script());
260 RefPtrWillBeRawPtr<ErrorEvent> errorEvent = nullptr;
261 m_script->evaluate(ScriptSourceCode(scriptLoader->script(), scriptLoader->responseURL()), &errorEvent);
263 m_script->rethrowExceptionFromImportedScript(errorEvent.release());
269 EventTarget* WorkerGlobalScope::errorEventTarget()
274 void WorkerGlobalScope::logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, int columnNumber, PassRefPtr<ScriptCallStack>)
276 thread()->workerReportingProxy().reportException(errorMessage, lineNumber, columnNumber, sourceURL);
279 void WorkerGlobalScope::reportBlockedScriptExecutionToInspector(const String& directiveText)
281 InspectorInstrumentation::scriptExecutionBlockedByCSP(this, directiveText);
284 void WorkerGlobalScope::addMessage(MessageSource source, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber, ScriptState* scriptState)
286 if (!isContextThread()) {
287 postTask(AddConsoleMessageTask::create(source, level, message));
290 thread()->workerReportingProxy().reportConsoleMessage(source, level, message, lineNumber, sourceURL);
291 addMessageToWorkerConsole(source, level, message, sourceURL, lineNumber, nullptr, scriptState);
294 void WorkerGlobalScope::addMessageToWorkerConsole(MessageSource source, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber, PassRefPtr<ScriptCallStack> callStack, ScriptState* scriptState)
296 ASSERT(isContextThread());
298 InspectorInstrumentation::addMessageToConsole(this, source, LogMessageType, level, message, callStack);
300 InspectorInstrumentation::addMessageToConsole(this, source, LogMessageType, level, message, sourceURL, lineNumber, 0, scriptState);
303 bool WorkerGlobalScope::isContextThread() const
305 return thread()->isCurrentThread();
308 bool WorkerGlobalScope::isJSExecutionForbidden() const
310 return m_script->isExecutionForbidden();
313 bool WorkerGlobalScope::idleNotification()
315 return script()->idleNotification();
318 WorkerEventQueue* WorkerGlobalScope::eventQueue() const
320 return m_eventQueue.get();
323 void WorkerGlobalScope::trace(Visitor* visitor)
325 visitor->trace(m_console);
326 visitor->trace(m_location);
327 visitor->trace(m_navigator);
328 visitor->trace(m_workerClients);
329 WillBeHeapSupplementable<WorkerGlobalScope>::trace(visitor);
330 ExecutionContext::trace(visitor);
333 } // namespace WebCore