Upstream version 10.39.225.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/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"
62
63 namespace blink {
64
65 class CloseWorkerGlobalScopeTask : public ExecutionContextTask {
66 public:
67     static PassOwnPtr<CloseWorkerGlobalScopeTask> create()
68     {
69         return adoptPtr(new CloseWorkerGlobalScopeTask);
70     }
71
72     virtual void performTask(ExecutionContext *context)
73     {
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();
77     }
78
79     virtual bool isCleanupTask() const { return true; }
80 };
81
82 WorkerGlobalScope::WorkerGlobalScope(const KURL& url, const String& userAgent, WorkerThread* thread, double timeOrigin, PassOwnPtrWillBeRawPtr<WorkerClients> workerClients)
83     : m_url(url)
84     , m_userAgent(userAgent)
85     , m_script(adoptPtr(new WorkerScriptController(*this)))
86     , m_thread(thread)
87     , m_workerInspectorController(adoptRefWillBeNoop(new WorkerInspectorController(this)))
88     , m_closing(false)
89     , m_eventQueue(WorkerEventQueue::create(this))
90     , m_workerClients(workerClients)
91     , m_timeOrigin(timeOrigin)
92     , m_messageStorage(ConsoleMessageStorage::createForWorker(this))
93 {
94     setSecurityOrigin(SecurityOrigin::create(url));
95     m_workerClients->reattachThread();
96     m_thread->setWorkerInspectorController(m_workerInspectorController.get());
97 }
98
99 WorkerGlobalScope::~WorkerGlobalScope()
100 {
101 }
102
103 void WorkerGlobalScope::applyContentSecurityPolicyFromString(const String& policy, ContentSecurityPolicyHeaderType contentSecurityPolicyType)
104 {
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);
110 }
111
112 ExecutionContext* WorkerGlobalScope::executionContext() const
113 {
114     return const_cast<WorkerGlobalScope*>(this);
115 }
116
117 const KURL& WorkerGlobalScope::virtualURL() const
118 {
119     return m_url;
120 }
121
122 KURL WorkerGlobalScope::virtualCompleteURL(const String& url) const
123 {
124     return completeURL(url);
125 }
126
127 KURL WorkerGlobalScope::completeURL(const String& url) const
128 {
129     // Always return a null URL when passed a null string.
130     // FIXME: Should we change the KURL constructor to have this behavior?
131     if (url.isNull())
132         return KURL();
133     // Always use UTF-8 in Workers.
134     return KURL(m_url, url);
135 }
136
137 String WorkerGlobalScope::userAgent(const KURL&) const
138 {
139     return m_userAgent;
140 }
141
142 void WorkerGlobalScope::disableEval(const String& errorMessage)
143 {
144     m_script->disableEval(errorMessage);
145 }
146
147 double WorkerGlobalScope::timerAlignmentInterval() const
148 {
149     return DOMTimer::visiblePageAlignmentInterval();
150 }
151
152 WorkerLocation* WorkerGlobalScope::location() const
153 {
154     if (!m_location)
155         m_location = WorkerLocation::create(m_url);
156     return m_location.get();
157 }
158
159 void WorkerGlobalScope::close()
160 {
161     if (m_closing)
162         return;
163
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.
167     m_closing = true;
168     postTask(CloseWorkerGlobalScopeTask::create());
169 }
170
171 WorkerConsole* WorkerGlobalScope::console()
172 {
173     if (!m_console)
174         m_console = WorkerConsole::create(this);
175     return m_console.get();
176 }
177
178 WorkerNavigator* WorkerGlobalScope::navigator() const
179 {
180     if (!m_navigator)
181         m_navigator = WorkerNavigator::create(m_userAgent);
182     return m_navigator.get();
183 }
184
185 void WorkerGlobalScope::postTask(PassOwnPtr<ExecutionContextTask> task)
186 {
187     thread()->postTask(task);
188 }
189
190 // FIXME: Called twice, from WorkerThreadShutdownFinishTask and WorkerGlobalScope::dispose.
191 void WorkerGlobalScope::clearInspector()
192 {
193     if (!m_workerInspectorController)
194         return;
195     thread()->setWorkerInspectorController(nullptr);
196     m_workerInspectorController->dispose();
197     m_workerInspectorController.clear();
198 }
199
200 void WorkerGlobalScope::dispose()
201 {
202     ASSERT(thread()->isCurrentThread());
203
204     m_eventQueue->close();
205     clearScript();
206     clearInspector();
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
212     // scope are gone.
213 }
214
215 void WorkerGlobalScope::importScripts(const Vector<String>& urls, ExceptionState& exceptionState)
216 {
217     ASSERT(contentSecurityPolicy());
218     ASSERT(executionContext());
219
220     ExecutionContext& executionContext = *this->executionContext();
221
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.");
228             return;
229         }
230         if (!contentSecurityPolicy()->allowScriptFromSource(url)) {
231             exceptionState.throwDOMException(NetworkError, "The script at '" + url.elidedString() + "' failed to load.");
232             return;
233         }
234         completedURLs.append(url);
235     }
236     Vector<KURL>::const_iterator end = completedURLs.end();
237
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);
242
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.");
246             return;
247         }
248
249         InspectorInstrumentation::scriptImported(&executionContext, scriptLoader->identifier(), scriptLoader->script());
250
251         RefPtrWillBeRawPtr<ErrorEvent> errorEvent = nullptr;
252         m_script->evaluate(ScriptSourceCode(scriptLoader->script(), scriptLoader->responseURL()), &errorEvent);
253         if (errorEvent) {
254             m_script->rethrowExceptionFromImportedScript(errorEvent.release(), exceptionState);
255             return;
256         }
257     }
258 }
259
260 EventTarget* WorkerGlobalScope::errorEventTarget()
261 {
262     return this;
263 }
264
265 void WorkerGlobalScope::logExceptionToConsole(const String& errorMessage, int, const String& sourceURL, int lineNumber, int columnNumber, PassRefPtrWillBeRawPtr<ScriptCallStack>)
266 {
267     thread()->workerReportingProxy().reportException(errorMessage, lineNumber, columnNumber, sourceURL);
268 }
269
270 void WorkerGlobalScope::reportBlockedScriptExecutionToInspector(const String& directiveText)
271 {
272     InspectorInstrumentation::scriptExecutionBlockedByCSP(this, directiveText);
273 }
274
275 void WorkerGlobalScope::addConsoleMessage(PassRefPtrWillBeRawPtr<ConsoleMessage> prpConsoleMessage)
276 {
277     RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = prpConsoleMessage;
278     if (!isContextThread()) {
279         postTask(AddConsoleMessageTask::create(consoleMessage->source(), consoleMessage->level(), consoleMessage->message()));
280         return;
281     }
282     thread()->workerReportingProxy().reportConsoleMessage(consoleMessage);
283     addMessageToWorkerConsole(consoleMessage.release());
284 }
285
286 void WorkerGlobalScope::addMessageToWorkerConsole(PassRefPtrWillBeRawPtr<ConsoleMessage> consoleMessage)
287 {
288     ASSERT(isContextThread());
289     m_messageStorage->reportMessage(consoleMessage);
290 }
291
292 bool WorkerGlobalScope::isContextThread() const
293 {
294     return thread()->isCurrentThread();
295 }
296
297 bool WorkerGlobalScope::isJSExecutionForbidden() const
298 {
299     return m_script->isExecutionForbidden();
300 }
301
302 bool WorkerGlobalScope::idleNotification()
303 {
304     return script()->idleNotification();
305 }
306
307 WorkerEventQueue* WorkerGlobalScope::eventQueue() const
308 {
309     return m_eventQueue.get();
310 }
311
312 void WorkerGlobalScope::countFeature(UseCounter::Feature) const
313 {
314     // FIXME: How should we count features for shared/service workers?
315 }
316
317 void WorkerGlobalScope::countDeprecation(UseCounter::Feature) const
318 {
319     // FIXME: How should we count features for shared/service workers?
320 }
321
322 ConsoleMessageStorage* WorkerGlobalScope::messageStorage()
323 {
324     return m_messageStorage.get();
325 }
326
327 void WorkerGlobalScope::trace(Visitor* visitor)
328 {
329 #if ENABLE(OILPAN)
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);
338 #endif
339     ExecutionContext::trace(visitor);
340     EventTargetWithInlineData::trace(visitor);
341 }
342
343 } // namespace blink