• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 Apple Inc. All Rights Reserved.
3  * Copyright (C) 2009, 2011 Google Inc. All Rights Reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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.
25  *
26  */
27 
28 #include "config.h"
29 #include "core/workers/WorkerGlobalScope.h"
30 
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/LocalDOMWindow.h"
48 #include "core/workers/WorkerNavigator.h"
49 #include "core/workers/WorkerClients.h"
50 #include "core/workers/WorkerConsole.h"
51 #include "core/workers/WorkerLocation.h"
52 #include "core/workers/WorkerNavigator.h"
53 #include "core/workers/WorkerReportingProxy.h"
54 #include "core/workers/WorkerScriptLoader.h"
55 #include "core/workers/WorkerThread.h"
56 #include "platform/network/ContentSecurityPolicyParsers.h"
57 #include "platform/weborigin/KURL.h"
58 #include "platform/weborigin/SecurityOrigin.h"
59 
60 namespace WebCore {
61 
62 class CloseWorkerGlobalScopeTask : public ExecutionContextTask {
63 public:
create()64     static PassOwnPtr<CloseWorkerGlobalScopeTask> create()
65     {
66         return adoptPtr(new CloseWorkerGlobalScopeTask);
67     }
68 
performTask(ExecutionContext * context)69     virtual void performTask(ExecutionContext *context)
70     {
71         WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(context);
72         // Notify parent that this context is closed. Parent is responsible for calling WorkerThread::stop().
73         workerGlobalScope->thread()->workerReportingProxy().workerGlobalScopeClosed();
74     }
75 
isCleanupTask() const76     virtual bool isCleanupTask() const { return true; }
77 };
78 
WorkerGlobalScope(const KURL & url,const String & userAgent,WorkerThread * thread,double timeOrigin,PassOwnPtrWillBeRawPtr<WorkerClients> workerClients)79 WorkerGlobalScope::WorkerGlobalScope(const KURL& url, const String& userAgent, WorkerThread* thread, double timeOrigin, PassOwnPtrWillBeRawPtr<WorkerClients> workerClients)
80     : m_url(url)
81     , m_userAgent(userAgent)
82     , m_script(adoptPtr(new WorkerScriptController(*this)))
83     , m_thread(thread)
84     , m_workerInspectorController(adoptPtr(new WorkerInspectorController(this)))
85     , m_closing(false)
86     , m_eventQueue(WorkerEventQueue::create(this))
87     , m_workerClients(workerClients)
88     , m_timeOrigin(timeOrigin)
89     , m_terminationObserver(0)
90 {
91     ScriptWrappable::init(this);
92     setClient(this);
93     setSecurityOrigin(SecurityOrigin::create(url));
94     m_workerClients->reattachThread();
95 }
96 
~WorkerGlobalScope()97 WorkerGlobalScope::~WorkerGlobalScope()
98 {
99 }
100 
applyContentSecurityPolicyFromString(const String & policy,ContentSecurityPolicyHeaderType contentSecurityPolicyType)101 void WorkerGlobalScope::applyContentSecurityPolicyFromString(const String& policy, ContentSecurityPolicyHeaderType contentSecurityPolicyType)
102 {
103     setContentSecurityPolicy(ContentSecurityPolicy::create(this));
104     contentSecurityPolicy()->didReceiveHeader(policy, contentSecurityPolicyType, ContentSecurityPolicyHeaderSourceHTTP);
105 }
106 
executionContext() const107 ExecutionContext* WorkerGlobalScope::executionContext() const
108 {
109     return const_cast<WorkerGlobalScope*>(this);
110 }
111 
virtualURL() const112 const KURL& WorkerGlobalScope::virtualURL() const
113 {
114     return m_url;
115 }
116 
virtualCompleteURL(const String & url) const117 KURL WorkerGlobalScope::virtualCompleteURL(const String& url) const
118 {
119     return completeURL(url);
120 }
121 
completeURL(const String & url) const122 KURL WorkerGlobalScope::completeURL(const String& url) const
123 {
124     // Always return a null URL when passed a null string.
125     // FIXME: Should we change the KURL constructor to have this behavior?
126     if (url.isNull())
127         return KURL();
128     // Always use UTF-8 in Workers.
129     return KURL(m_url, url);
130 }
131 
userAgent(const KURL &) const132 String WorkerGlobalScope::userAgent(const KURL&) const
133 {
134     return m_userAgent;
135 }
136 
disableEval(const String & errorMessage)137 void WorkerGlobalScope::disableEval(const String& errorMessage)
138 {
139     m_script->disableEval(errorMessage);
140 }
141 
timerAlignmentInterval() const142 double WorkerGlobalScope::timerAlignmentInterval() const
143 {
144     return DOMTimer::visiblePageAlignmentInterval();
145 }
146 
location() const147 WorkerLocation* WorkerGlobalScope::location() const
148 {
149     if (!m_location)
150         m_location = WorkerLocation::create(m_url);
151     return m_location.get();
152 }
153 
close()154 void WorkerGlobalScope::close()
155 {
156     if (m_closing)
157         return;
158 
159     // Let current script run to completion but prevent future script evaluations.
160     // After m_closing is set, all the tasks in the queue continue to be fetched but only
161     // tasks with isCleanupTask()==true will be executed.
162     m_closing = true;
163     postTask(CloseWorkerGlobalScopeTask::create());
164 }
165 
console()166 WorkerConsole* WorkerGlobalScope::console()
167 {
168     if (!m_console)
169         m_console = WorkerConsole::create(this);
170     return m_console.get();
171 }
172 
navigator() const173 WorkerNavigator* WorkerGlobalScope::navigator() const
174 {
175     if (!m_navigator)
176         m_navigator = WorkerNavigator::create(m_userAgent);
177     return m_navigator.get();
178 }
179 
postTask(PassOwnPtr<ExecutionContextTask> task)180 void WorkerGlobalScope::postTask(PassOwnPtr<ExecutionContextTask> task)
181 {
182     thread()->runLoop().postTask(task);
183 }
184 
clearInspector()185 void WorkerGlobalScope::clearInspector()
186 {
187     m_workerInspectorController.clear();
188 }
189 
registerTerminationObserver(TerminationObserver * observer)190 void WorkerGlobalScope::registerTerminationObserver(TerminationObserver* observer)
191 {
192     ASSERT(!m_terminationObserver);
193     ASSERT(observer);
194     m_terminationObserver = observer;
195 }
196 
unregisterTerminationObserver(TerminationObserver * observer)197 void WorkerGlobalScope::unregisterTerminationObserver(TerminationObserver* observer)
198 {
199     ASSERT(observer);
200     ASSERT(m_terminationObserver == observer);
201     m_terminationObserver = 0;
202 }
203 
wasRequestedToTerminate()204 void WorkerGlobalScope::wasRequestedToTerminate()
205 {
206     if (m_terminationObserver)
207         m_terminationObserver->wasRequestedToTerminate();
208 }
209 
dispose()210 void WorkerGlobalScope::dispose()
211 {
212     ASSERT(thread()->isCurrentThread());
213 
214     m_eventQueue->close();
215     clearScript();
216     clearInspector();
217     setClient(0);
218 
219     // We do not clear the thread field of the
220     // WorkerGlobalScope. Other objects keep the worker global scope
221     // alive because they need its thread field to check that work is
222     // being carried out on the right thread. We therefore cannot clear
223     // the thread field before all references to the worker global
224     // scope are gone.
225 }
226 
importScripts(const Vector<String> & urls,ExceptionState & exceptionState)227 void WorkerGlobalScope::importScripts(const Vector<String>& urls, ExceptionState& exceptionState)
228 {
229     ASSERT(contentSecurityPolicy());
230     ASSERT(executionContext());
231 
232     ExecutionContext& executionContext = *this->executionContext();
233 
234     Vector<String>::const_iterator urlsEnd = urls.end();
235     Vector<KURL> completedURLs;
236     for (Vector<String>::const_iterator it = urls.begin(); it != urlsEnd; ++it) {
237         const KURL& url = executionContext.completeURL(*it);
238         if (!url.isValid()) {
239             exceptionState.throwDOMException(SyntaxError, "The URL '" + *it + "' is invalid.");
240             return;
241         }
242         if (!contentSecurityPolicy()->allowScriptFromSource(url)) {
243             exceptionState.throwDOMException(NetworkError, "The script at '" + url.elidedString() + "' failed to load.");
244             return;
245         }
246         completedURLs.append(url);
247     }
248     Vector<KURL>::const_iterator end = completedURLs.end();
249 
250     for (Vector<KURL>::const_iterator it = completedURLs.begin(); it != end; ++it) {
251         RefPtr<WorkerScriptLoader> scriptLoader(WorkerScriptLoader::create());
252         scriptLoader->setTargetType(ResourceRequest::TargetIsScript);
253         scriptLoader->loadSynchronously(executionContext, *it, AllowCrossOriginRequests);
254 
255         // If the fetching attempt failed, throw a NetworkError exception and abort all these steps.
256         if (scriptLoader->failed()) {
257             exceptionState.throwDOMException(NetworkError, "The script at '" + it->elidedString() + "' failed to load.");
258             return;
259         }
260 
261         InspectorInstrumentation::scriptImported(&executionContext, scriptLoader->identifier(), scriptLoader->script());
262 
263         RefPtrWillBeRawPtr<ErrorEvent> errorEvent = nullptr;
264         m_script->evaluate(ScriptSourceCode(scriptLoader->script(), scriptLoader->responseURL()), &errorEvent);
265         if (errorEvent) {
266             m_script->rethrowExceptionFromImportedScript(errorEvent.release());
267             return;
268         }
269     }
270 }
271 
errorEventTarget()272 EventTarget* WorkerGlobalScope::errorEventTarget()
273 {
274     return this;
275 }
276 
logExceptionToConsole(const String & errorMessage,const String & sourceURL,int lineNumber,int columnNumber,PassRefPtrWillBeRawPtr<ScriptCallStack>)277 void WorkerGlobalScope::logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, int columnNumber, PassRefPtrWillBeRawPtr<ScriptCallStack>)
278 {
279     thread()->workerReportingProxy().reportException(errorMessage, lineNumber, columnNumber, sourceURL);
280 }
281 
reportBlockedScriptExecutionToInspector(const String & directiveText)282 void WorkerGlobalScope::reportBlockedScriptExecutionToInspector(const String& directiveText)
283 {
284     InspectorInstrumentation::scriptExecutionBlockedByCSP(this, directiveText);
285 }
286 
addMessage(MessageSource source,MessageLevel level,const String & message,const String & sourceURL,unsigned lineNumber,ScriptState * scriptState)287 void WorkerGlobalScope::addMessage(MessageSource source, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber, ScriptState* scriptState)
288 {
289     if (!isContextThread()) {
290         postTask(AddConsoleMessageTask::create(source, level, message));
291         return;
292     }
293     thread()->workerReportingProxy().reportConsoleMessage(source, level, message, lineNumber, sourceURL);
294     addMessageToWorkerConsole(source, level, message, sourceURL, lineNumber, nullptr, scriptState);
295 }
296 
addMessageToWorkerConsole(MessageSource source,MessageLevel level,const String & message,const String & sourceURL,unsigned lineNumber,PassRefPtrWillBeRawPtr<ScriptCallStack> callStack,ScriptState * scriptState)297 void WorkerGlobalScope::addMessageToWorkerConsole(MessageSource source, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber, PassRefPtrWillBeRawPtr<ScriptCallStack> callStack, ScriptState* scriptState)
298 {
299     ASSERT(isContextThread());
300     if (callStack)
301         InspectorInstrumentation::addMessageToConsole(this, source, LogMessageType, level, message, callStack);
302     else
303         InspectorInstrumentation::addMessageToConsole(this, source, LogMessageType, level, message, sourceURL, lineNumber, 0, scriptState);
304 }
305 
isContextThread() const306 bool WorkerGlobalScope::isContextThread() const
307 {
308     return thread()->isCurrentThread();
309 }
310 
isJSExecutionForbidden() const311 bool WorkerGlobalScope::isJSExecutionForbidden() const
312 {
313     return m_script->isExecutionForbidden();
314 }
315 
idleNotification()316 bool WorkerGlobalScope::idleNotification()
317 {
318     return script()->idleNotification();
319 }
320 
eventQueue() const321 WorkerEventQueue* WorkerGlobalScope::eventQueue() const
322 {
323     return m_eventQueue.get();
324 }
325 
countFeature(UseCounter::Feature) const326 void WorkerGlobalScope::countFeature(UseCounter::Feature) const
327 {
328     // FIXME: How should we count features for shared/service workers?
329 }
330 
countDeprecation(UseCounter::Feature) const331 void WorkerGlobalScope::countDeprecation(UseCounter::Feature) const
332 {
333     // FIXME: How should we count features for shared/service workers?
334 }
335 
trace(Visitor * visitor)336 void WorkerGlobalScope::trace(Visitor* visitor)
337 {
338     visitor->trace(m_console);
339     visitor->trace(m_location);
340     visitor->trace(m_navigator);
341     visitor->trace(m_eventQueue);
342     visitor->trace(m_workerClients);
343     WillBeHeapSupplementable<WorkerGlobalScope>::trace(visitor);
344     ExecutionContext::trace(visitor);
345     EventTargetWithInlineData::trace(visitor);
346 }
347 
348 } // namespace WebCore
349