Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / workers / WorkerGlobalScope.cpp
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/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"
57
58 namespace WebCore {
59
60 class CloseWorkerGlobalScopeTask : public ExecutionContextTask {
61 public:
62     static PassOwnPtr<CloseWorkerGlobalScopeTask> create()
63     {
64         return adoptPtr(new CloseWorkerGlobalScopeTask);
65     }
66
67     virtual void performTask(ExecutionContext *context)
68     {
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();
72     }
73
74     virtual bool isCleanupTask() const { return true; }
75 };
76
77 WorkerGlobalScope::WorkerGlobalScope(const KURL& url, const String& userAgent, WorkerThread* thread, double timeOrigin, PassOwnPtrWillBeRawPtr<WorkerClients> workerClients)
78     : m_url(url)
79     , m_userAgent(userAgent)
80     , m_script(adoptPtr(new WorkerScriptController(*this)))
81     , m_thread(thread)
82     , m_workerInspectorController(adoptPtr(new WorkerInspectorController(this)))
83     , m_closing(false)
84     , m_eventQueue(WorkerEventQueue::create(this))
85     , m_workerClients(workerClients)
86     , m_timeOrigin(timeOrigin)
87     , m_terminationObserver(0)
88 {
89     ScriptWrappable::init(this);
90     setClient(this);
91     setSecurityOrigin(SecurityOrigin::create(url));
92     m_workerClients->reattachThread();
93 }
94
95 WorkerGlobalScope::~WorkerGlobalScope()
96 {
97 }
98
99 void WorkerGlobalScope::applyContentSecurityPolicyFromString(const String& policy, ContentSecurityPolicyHeaderType contentSecurityPolicyType)
100 {
101     setContentSecurityPolicy(ContentSecurityPolicy::create(this));
102     contentSecurityPolicy()->didReceiveHeader(policy, contentSecurityPolicyType, ContentSecurityPolicyHeaderSourceHTTP);
103 }
104
105 ExecutionContext* WorkerGlobalScope::executionContext() const
106 {
107     return const_cast<WorkerGlobalScope*>(this);
108 }
109
110 const KURL& WorkerGlobalScope::virtualURL() const
111 {
112     return m_url;
113 }
114
115 KURL WorkerGlobalScope::virtualCompleteURL(const String& url) const
116 {
117     return completeURL(url);
118 }
119
120 KURL WorkerGlobalScope::completeURL(const String& url) const
121 {
122     // Always return a null URL when passed a null string.
123     // FIXME: Should we change the KURL constructor to have this behavior?
124     if (url.isNull())
125         return KURL();
126     // Always use UTF-8 in Workers.
127     return KURL(m_url, url);
128 }
129
130 String WorkerGlobalScope::userAgent(const KURL&) const
131 {
132     return m_userAgent;
133 }
134
135 void WorkerGlobalScope::disableEval(const String& errorMessage)
136 {
137     m_script->disableEval(errorMessage);
138 }
139
140 double WorkerGlobalScope::timerAlignmentInterval() const
141 {
142     return DOMTimer::visiblePageAlignmentInterval();
143 }
144
145 WorkerLocation* WorkerGlobalScope::location() const
146 {
147     if (!m_location)
148         m_location = WorkerLocation::create(m_url);
149     return m_location.get();
150 }
151
152 void WorkerGlobalScope::close()
153 {
154     if (m_closing)
155         return;
156
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.
160     m_closing = true;
161     postTask(CloseWorkerGlobalScopeTask::create());
162 }
163
164 WorkerConsole* WorkerGlobalScope::console()
165 {
166     if (!m_console)
167         m_console = WorkerConsole::create(this);
168     return m_console.get();
169 }
170
171 WorkerNavigator* WorkerGlobalScope::navigator() const
172 {
173     if (!m_navigator)
174         m_navigator = WorkerNavigator::create(m_userAgent);
175     return m_navigator.get();
176 }
177
178 void WorkerGlobalScope::postTask(PassOwnPtr<ExecutionContextTask> task)
179 {
180     thread()->runLoop().postTask(task);
181 }
182
183 void WorkerGlobalScope::clearInspector()
184 {
185     m_workerInspectorController.clear();
186 }
187
188 void WorkerGlobalScope::registerTerminationObserver(TerminationObserver* observer)
189 {
190     ASSERT(!m_terminationObserver);
191     ASSERT(observer);
192     m_terminationObserver = observer;
193 }
194
195 void WorkerGlobalScope::unregisterTerminationObserver(TerminationObserver* observer)
196 {
197     ASSERT(observer);
198     ASSERT(m_terminationObserver == observer);
199     m_terminationObserver = 0;
200 }
201
202 void WorkerGlobalScope::wasRequestedToTerminate()
203 {
204     if (m_terminationObserver)
205         m_terminationObserver->wasRequestedToTerminate();
206 }
207
208 void WorkerGlobalScope::dispose()
209 {
210     ASSERT(thread()->isCurrentThread());
211
212     clearScript();
213     clearInspector();
214     setClient(0);
215
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
221     // scope are gone.
222 }
223
224 void WorkerGlobalScope::importScripts(const Vector<String>& urls, ExceptionState& exceptionState)
225 {
226     ASSERT(contentSecurityPolicy());
227     ASSERT(executionContext());
228
229     ExecutionContext& executionContext = *this->executionContext();
230
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.");
237             return;
238         }
239         if (!contentSecurityPolicy()->allowScriptFromSource(url)) {
240             exceptionState.throwDOMException(NetworkError, "The script at '" + url.elidedString() + "' failed to load.");
241             return;
242         }
243         completedURLs.append(url);
244     }
245     Vector<KURL>::const_iterator end = completedURLs.end();
246
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);
251
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.");
255             return;
256         }
257
258         InspectorInstrumentation::scriptImported(&executionContext, scriptLoader->identifier(), scriptLoader->script());
259
260         RefPtrWillBeRawPtr<ErrorEvent> errorEvent = nullptr;
261         m_script->evaluate(ScriptSourceCode(scriptLoader->script(), scriptLoader->responseURL()), &errorEvent);
262         if (errorEvent) {
263             m_script->rethrowExceptionFromImportedScript(errorEvent.release());
264             return;
265         }
266     }
267 }
268
269 EventTarget* WorkerGlobalScope::errorEventTarget()
270 {
271     return this;
272 }
273
274 void WorkerGlobalScope::logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, int columnNumber, PassRefPtr<ScriptCallStack>)
275 {
276     thread()->workerReportingProxy().reportException(errorMessage, lineNumber, columnNumber, sourceURL);
277 }
278
279 void WorkerGlobalScope::reportBlockedScriptExecutionToInspector(const String& directiveText)
280 {
281     InspectorInstrumentation::scriptExecutionBlockedByCSP(this, directiveText);
282 }
283
284 void WorkerGlobalScope::addMessage(MessageSource source, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber, ScriptState* scriptState)
285 {
286     if (!isContextThread()) {
287         postTask(AddConsoleMessageTask::create(source, level, message));
288         return;
289     }
290     thread()->workerReportingProxy().reportConsoleMessage(source, level, message, lineNumber, sourceURL);
291     addMessageToWorkerConsole(source, level, message, sourceURL, lineNumber, nullptr, scriptState);
292 }
293
294 void WorkerGlobalScope::addMessageToWorkerConsole(MessageSource source, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber, PassRefPtr<ScriptCallStack> callStack, ScriptState* scriptState)
295 {
296     ASSERT(isContextThread());
297     if (callStack)
298         InspectorInstrumentation::addMessageToConsole(this, source, LogMessageType, level, message, callStack);
299     else
300         InspectorInstrumentation::addMessageToConsole(this, source, LogMessageType, level, message, sourceURL, lineNumber, 0, scriptState);
301 }
302
303 bool WorkerGlobalScope::isContextThread() const
304 {
305     return thread()->isCurrentThread();
306 }
307
308 bool WorkerGlobalScope::isJSExecutionForbidden() const
309 {
310     return m_script->isExecutionForbidden();
311 }
312
313 bool WorkerGlobalScope::idleNotification()
314 {
315     return script()->idleNotification();
316 }
317
318 WorkerEventQueue* WorkerGlobalScope::eventQueue() const
319 {
320     return m_eventQueue.get();
321 }
322
323 void WorkerGlobalScope::trace(Visitor* visitor)
324 {
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);
331 }
332
333 } // namespace WebCore