Upstream version 11.40.277.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, const SecurityOrigin* starterOrigin, 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     if (starterOrigin)
96         securityOrigin()->transferPrivilegesFrom(*starterOrigin);
97
98     m_workerClients->reattachThread();
99     m_thread->setWorkerInspectorController(m_workerInspectorController.get());
100 }
101
102 WorkerGlobalScope::~WorkerGlobalScope()
103 {
104 }
105
106 void WorkerGlobalScope::applyContentSecurityPolicyFromString(const String& policy, ContentSecurityPolicyHeaderType contentSecurityPolicyType)
107 {
108     // FIXME: This doesn't match the CSP2 spec's Worker behavior (see https://w3c.github.io/webappsec/specs/content-security-policy/#processing-model-workers)
109     RefPtr<ContentSecurityPolicy> csp = ContentSecurityPolicy::create();
110     csp->didReceiveHeader(policy, contentSecurityPolicyType, ContentSecurityPolicyHeaderSourceHTTP);
111     csp->bindToExecutionContext(executionContext());
112     setContentSecurityPolicy(csp);
113 }
114
115 ExecutionContext* WorkerGlobalScope::executionContext() const
116 {
117     return const_cast<WorkerGlobalScope*>(this);
118 }
119
120 const KURL& WorkerGlobalScope::virtualURL() const
121 {
122     return m_url;
123 }
124
125 KURL WorkerGlobalScope::virtualCompleteURL(const String& url) const
126 {
127     return completeURL(url);
128 }
129
130 KURL WorkerGlobalScope::completeURL(const String& url) const
131 {
132     // Always return a null URL when passed a null string.
133     // FIXME: Should we change the KURL constructor to have this behavior?
134     if (url.isNull())
135         return KURL();
136     // Always use UTF-8 in Workers.
137     return KURL(m_url, url);
138 }
139
140 String WorkerGlobalScope::userAgent(const KURL&) const
141 {
142     return m_userAgent;
143 }
144
145 void WorkerGlobalScope::disableEval(const String& errorMessage)
146 {
147     m_script->disableEval(errorMessage);
148 }
149
150 double WorkerGlobalScope::timerAlignmentInterval() const
151 {
152     return DOMTimer::visiblePageAlignmentInterval();
153 }
154
155 WorkerLocation* WorkerGlobalScope::location() const
156 {
157     if (!m_location)
158         m_location = WorkerLocation::create(m_url);
159     return m_location.get();
160 }
161
162 void WorkerGlobalScope::close()
163 {
164     if (m_closing)
165         return;
166
167     // Let current script run to completion but prevent future script evaluations.
168     // After m_closing is set, all the tasks in the queue continue to be fetched but only
169     // tasks with isCleanupTask()==true will be executed.
170     m_closing = true;
171     postTask(CloseWorkerGlobalScopeTask::create());
172 }
173
174 WorkerConsole* WorkerGlobalScope::console()
175 {
176     if (!m_console)
177         m_console = WorkerConsole::create(this);
178     return m_console.get();
179 }
180
181 WorkerNavigator* WorkerGlobalScope::navigator() const
182 {
183     if (!m_navigator)
184         m_navigator = WorkerNavigator::create(m_userAgent);
185     return m_navigator.get();
186 }
187
188 void WorkerGlobalScope::postTask(PassOwnPtr<ExecutionContextTask> task)
189 {
190     thread()->postTask(task);
191 }
192
193 // FIXME: Called twice, from WorkerThreadShutdownFinishTask and WorkerGlobalScope::dispose.
194 void WorkerGlobalScope::clearInspector()
195 {
196     if (!m_workerInspectorController)
197         return;
198     thread()->setWorkerInspectorController(nullptr);
199     m_workerInspectorController->dispose();
200     m_workerInspectorController.clear();
201 }
202
203 void WorkerGlobalScope::dispose()
204 {
205     ASSERT(thread()->isCurrentThread());
206
207     m_eventQueue->close();
208     clearScript();
209     clearInspector();
210     // We do not clear the thread field of the
211     // WorkerGlobalScope. Other objects keep the worker global scope
212     // alive because they need its thread field to check that work is
213     // being carried out on the right thread. We therefore cannot clear
214     // the thread field before all references to the worker global
215     // scope are gone.
216 }
217
218 void WorkerGlobalScope::didEvaluateWorkerScript()
219 {
220 }
221
222 void WorkerGlobalScope::importScripts(const Vector<String>& urls, ExceptionState& exceptionState)
223 {
224     ASSERT(contentSecurityPolicy());
225     ASSERT(executionContext());
226
227     ExecutionContext& executionContext = *this->executionContext();
228
229     Vector<KURL> completedURLs;
230     for (const String& urlString : urls) {
231         const KURL& url = executionContext.completeURL(urlString);
232         if (!url.isValid()) {
233             exceptionState.throwDOMException(SyntaxError, "The URL '" + urlString + "' is invalid.");
234             return;
235         }
236         if (!contentSecurityPolicy()->allowScriptFromSource(url)) {
237             exceptionState.throwDOMException(NetworkError, "The script at '" + url.elidedString() + "' failed to load.");
238             return;
239         }
240         completedURLs.append(url);
241     }
242
243     for (const KURL& completeURL : completedURLs) {
244         RefPtr<WorkerScriptLoader> scriptLoader(WorkerScriptLoader::create());
245         scriptLoader->setRequestContext(blink::WebURLRequest::RequestContextScript);
246         scriptLoader->loadSynchronously(executionContext, completeURL, AllowCrossOriginRequests);
247
248         // If the fetching attempt failed, throw a NetworkError exception and abort all these steps.
249         if (scriptLoader->failed()) {
250             exceptionState.throwDOMException(NetworkError, "The script at '" + completeURL.elidedString() + "' failed to load.");
251             return;
252         }
253
254         InspectorInstrumentation::scriptImported(&executionContext, scriptLoader->identifier(), scriptLoader->script());
255
256         RefPtrWillBeRawPtr<ErrorEvent> errorEvent = nullptr;
257         m_script->evaluate(ScriptSourceCode(scriptLoader->script(), scriptLoader->responseURL()), &errorEvent);
258         if (errorEvent) {
259             m_script->rethrowExceptionFromImportedScript(errorEvent.release(), exceptionState);
260             return;
261         }
262     }
263 }
264
265 EventTarget* WorkerGlobalScope::errorEventTarget()
266 {
267     return this;
268 }
269
270 void WorkerGlobalScope::logExceptionToConsole(const String& errorMessage, int, const String& sourceURL, int lineNumber, int columnNumber, PassRefPtrWillBeRawPtr<ScriptCallStack>)
271 {
272     thread()->workerReportingProxy().reportException(errorMessage, lineNumber, columnNumber, sourceURL);
273 }
274
275 void WorkerGlobalScope::reportBlockedScriptExecutionToInspector(const String& directiveText)
276 {
277     InspectorInstrumentation::scriptExecutionBlockedByCSP(this, directiveText);
278 }
279
280 void WorkerGlobalScope::addConsoleMessage(PassRefPtrWillBeRawPtr<ConsoleMessage> prpConsoleMessage)
281 {
282     RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = prpConsoleMessage;
283     if (!isContextThread()) {
284         postTask(AddConsoleMessageTask::create(consoleMessage->source(), consoleMessage->level(), consoleMessage->message()));
285         return;
286     }
287     thread()->workerReportingProxy().reportConsoleMessage(consoleMessage);
288     addMessageToWorkerConsole(consoleMessage.release());
289 }
290
291 void WorkerGlobalScope::addMessageToWorkerConsole(PassRefPtrWillBeRawPtr<ConsoleMessage> consoleMessage)
292 {
293     ASSERT(isContextThread());
294     m_messageStorage->reportMessage(consoleMessage);
295 }
296
297 bool WorkerGlobalScope::isContextThread() const
298 {
299     return thread()->isCurrentThread();
300 }
301
302 bool WorkerGlobalScope::isJSExecutionForbidden() const
303 {
304     return m_script->isExecutionForbidden();
305 }
306
307 bool WorkerGlobalScope::idleNotification()
308 {
309     return script()->idleNotification();
310 }
311
312 WorkerEventQueue* WorkerGlobalScope::eventQueue() const
313 {
314     return m_eventQueue.get();
315 }
316
317 void WorkerGlobalScope::countFeature(UseCounter::Feature) const
318 {
319     // FIXME: How should we count features for shared/service workers?
320 }
321
322 void WorkerGlobalScope::countDeprecation(UseCounter::Feature) const
323 {
324     // FIXME: How should we count features for shared/service workers?
325 }
326
327 ConsoleMessageStorage* WorkerGlobalScope::messageStorage()
328 {
329     return m_messageStorage.get();
330 }
331
332 void WorkerGlobalScope::trace(Visitor* visitor)
333 {
334 #if ENABLE(OILPAN)
335     visitor->trace(m_console);
336     visitor->trace(m_location);
337     visitor->trace(m_navigator);
338     visitor->trace(m_workerInspectorController);
339     visitor->trace(m_eventQueue);
340     visitor->trace(m_workerClients);
341     visitor->trace(m_messageStorage);
342     HeapSupplementable<WorkerGlobalScope>::trace(visitor);
343 #endif
344     ExecutionContext::trace(visitor);
345     EventTargetWithInlineData::trace(visitor);
346 }
347
348 } // namespace blink