finally blocks should not set the exception stack trace when re-throwing the exception.
[WebKit-https.git] / Source / WebCore / 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 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 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 "WorkerGlobalScope.h"
30
31 #include "ActiveDOMObject.h"
32 #include "ContentSecurityPolicy.h"
33 #include "DOMTimer.h"
34 #include "DOMURL.h"
35 #include "DOMWindow.h"
36 #include "ErrorEvent.h"
37 #include "Event.h"
38 #include "EventException.h"
39 #include "ExceptionCode.h"
40 #include "InspectorConsoleInstrumentation.h"
41 #include "MessagePort.h"
42 #include "ScheduledAction.h"
43 #include "ScriptSourceCode.h"
44 #include "SecurityOrigin.h"
45 #include "SecurityOriginPolicy.h"
46 #include "URL.h"
47 #include "WorkerInspectorController.h"
48 #include "WorkerLocation.h"
49 #include "WorkerNavigator.h"
50 #include "WorkerObjectProxy.h"
51 #include "WorkerScriptLoader.h"
52 #include "WorkerThread.h"
53 #include "WorkerThreadableLoader.h"
54 #include "XMLHttpRequestException.h"
55 #include <bindings/ScriptValue.h>
56 #include <inspector/ConsoleMessage.h>
57 #include <inspector/ScriptCallStack.h>
58 #include <wtf/RefPtr.h>
59
60 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
61 #include "NotificationCenter.h"
62 #endif
63
64 using namespace Inspector;
65
66 namespace WebCore {
67
68 WorkerGlobalScope::WorkerGlobalScope(const URL& url, const String& userAgent, WorkerThread& thread, PassRefPtr<SecurityOrigin> topOrigin)
69     : m_url(url)
70     , m_userAgent(userAgent)
71     , m_script(std::make_unique<WorkerScriptController>(this))
72     , m_thread(thread)
73     , m_workerInspectorController(std::make_unique<WorkerInspectorController>(*this))
74     , m_closing(false)
75     , m_eventQueue(*this)
76     , m_topOrigin(topOrigin)
77 {
78     setSecurityOriginPolicy(SecurityOriginPolicy::create(SecurityOrigin::create(url)));
79 }
80
81 WorkerGlobalScope::~WorkerGlobalScope()
82 {
83     ASSERT(currentThread() == thread().threadID());
84
85     // Make sure we have no observers.
86     notifyObserversOfStop();
87
88     // Notify proxy that we are going away. This can free the WorkerThread object, so do not access it after this.
89     thread().workerReportingProxy().workerGlobalScopeDestroyed();
90 }
91
92 void WorkerGlobalScope::applyContentSecurityPolicyFromString(const String& policy, ContentSecurityPolicy::HeaderType contentSecurityPolicyType)
93 {
94     setContentSecurityPolicy(std::make_unique<ContentSecurityPolicy>(this));
95     contentSecurityPolicy()->didReceiveHeader(policy, contentSecurityPolicyType);
96 }
97
98 URL WorkerGlobalScope::completeURL(const String& url) const
99 {
100     // Always return a null URL when passed a null string.
101     // FIXME: Should we change the URL constructor to have this behavior?
102     if (url.isNull())
103         return URL();
104     // Always use UTF-8 in Workers.
105     return URL(m_url, url);
106 }
107
108 String WorkerGlobalScope::userAgent(const URL&) const
109 {
110     return m_userAgent;
111 }
112
113 void WorkerGlobalScope::disableEval(const String& errorMessage)
114 {
115     m_script->disableEval(errorMessage);
116 }
117
118 WorkerLocation* WorkerGlobalScope::location() const
119 {
120     if (!m_location)
121         m_location = WorkerLocation::create(m_url);
122     return m_location.get();
123 }
124
125 void WorkerGlobalScope::close()
126 {
127     if (m_closing)
128         return;
129
130     // Let current script run to completion but prevent future script evaluations.
131     // After m_closing is set, all the tasks in the queue continue to be fetched but only
132     // tasks with isCleanupTask()==true will be executed.
133     m_closing = true;
134     postTask({ ScriptExecutionContext::Task::CleanupTask, [] (ScriptExecutionContext& context) {
135         ASSERT_WITH_SECURITY_IMPLICATION(is<WorkerGlobalScope>(context));
136         WorkerGlobalScope& workerGlobalScope = downcast<WorkerGlobalScope>(context);
137         // Notify parent that this context is closed. Parent is responsible for calling WorkerThread::stop().
138         workerGlobalScope.thread().workerReportingProxy().workerGlobalScopeClosed();
139     } });
140 }
141
142 WorkerNavigator* WorkerGlobalScope::navigator() const
143 {
144     if (!m_navigator)
145         m_navigator = WorkerNavigator::create(m_userAgent);
146     return m_navigator.get();
147 }
148
149 void WorkerGlobalScope::postTask(Task task)
150 {
151     thread().runLoop().postTask(WTF::move(task));
152 }
153
154 int WorkerGlobalScope::setTimeout(std::unique_ptr<ScheduledAction> action, int timeout)
155 {
156     return DOMTimer::install(*this, WTF::move(action), timeout, true);
157 }
158
159 void WorkerGlobalScope::clearTimeout(int timeoutId)
160 {
161     DOMTimer::removeById(*this, timeoutId);
162 }
163
164 int WorkerGlobalScope::setInterval(std::unique_ptr<ScheduledAction> action, int timeout)
165 {
166     return DOMTimer::install(*this, WTF::move(action), timeout, false);
167 }
168
169 void WorkerGlobalScope::clearInterval(int timeoutId)
170 {
171     DOMTimer::removeById(*this, timeoutId);
172 }
173
174 void WorkerGlobalScope::importScripts(const Vector<String>& urls, ExceptionCode& ec)
175 {
176     ASSERT(contentSecurityPolicy());
177     ec = 0;
178     Vector<URL> completedURLs;
179     for (auto& entry : urls) {
180         URL url = scriptExecutionContext()->completeURL(entry);
181         if (!url.isValid()) {
182             ec = SYNTAX_ERR;
183             return;
184         }
185         completedURLs.append(WTF::move(url));
186     }
187
188     for (auto& url : completedURLs) {
189         Ref<WorkerScriptLoader> scriptLoader = WorkerScriptLoader::create();
190         scriptLoader->loadSynchronously(scriptExecutionContext(), url, AllowCrossOriginRequests);
191
192         // If the fetching attempt failed, throw a NETWORK_ERR exception and abort all these steps.
193         if (scriptLoader->failed()) {
194             ec = XMLHttpRequestException::NETWORK_ERR;
195             return;
196         }
197
198         InspectorInstrumentation::scriptImported(scriptExecutionContext(), scriptLoader->identifier(), scriptLoader->script());
199
200         JSC::Exception* exception;
201         m_script->evaluate(ScriptSourceCode(scriptLoader->script(), scriptLoader->responseURL()), exception);
202         if (exception) {
203             m_script->setException(exception);
204             return;
205         }
206     }
207 }
208
209 EventTarget* WorkerGlobalScope::errorEventTarget()
210 {
211     return this;
212 }
213
214 void WorkerGlobalScope::logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, int columnNumber, RefPtr<ScriptCallStack>&&)
215 {
216     thread().workerReportingProxy().postExceptionToWorkerObject(errorMessage, lineNumber, columnNumber, sourceURL);
217 }
218
219 void WorkerGlobalScope::addConsoleMessage(MessageSource source, MessageLevel level, const String& message, unsigned long requestIdentifier)
220 {
221     if (!isContextThread()) {
222         postTask(AddConsoleMessageTask(source, level, StringCapture(message)));
223         return;
224     }
225
226     thread().workerReportingProxy().postConsoleMessageToWorkerObject(source, level, message, 0, 0, String());
227     addMessageToWorkerConsole(source, level, message, String(), 0, 0, 0, 0, requestIdentifier);
228 }
229
230 void WorkerGlobalScope::addMessage(MessageSource source, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber, unsigned columnNumber, RefPtr<ScriptCallStack>&& callStack, JSC::ExecState* state, unsigned long requestIdentifier)
231 {
232     if (!isContextThread()) {
233         postTask(AddConsoleMessageTask(source, level, StringCapture(message)));
234         return;
235     }
236
237     thread().workerReportingProxy().postConsoleMessageToWorkerObject(source, level, message, lineNumber, columnNumber, sourceURL);
238     addMessageToWorkerConsole(source, level, message, sourceURL, lineNumber, columnNumber, WTF::move(callStack), state, requestIdentifier);
239 }
240
241 void WorkerGlobalScope::addMessageToWorkerConsole(MessageSource source, MessageLevel level, const String& messageText, const String& suggestedURL, unsigned suggestedLineNumber, unsigned suggestedColumnNumber, RefPtr<ScriptCallStack>&& callStack, JSC::ExecState* state, unsigned long requestIdentifier)
242 {
243     ASSERT(isContextThread());
244
245     std::unique_ptr<Inspector::ConsoleMessage> message;
246
247     if (callStack)
248         message = std::make_unique<Inspector::ConsoleMessage>(source, MessageType::Log, level, messageText, WTF::move(callStack), requestIdentifier);
249     else
250         message = std::make_unique<Inspector::ConsoleMessage>(source, MessageType::Log, level, messageText, suggestedURL, suggestedLineNumber, suggestedColumnNumber, state, requestIdentifier);
251
252     InspectorInstrumentation::addMessageToConsole(this, WTF::move(message));
253 }
254
255 bool WorkerGlobalScope::isContextThread() const
256 {
257     return currentThread() == thread().threadID();
258 }
259
260 bool WorkerGlobalScope::isJSExecutionForbidden() const
261 {
262     return m_script->isExecutionForbidden();
263 }
264
265 WorkerGlobalScope::Observer::Observer(WorkerGlobalScope* context)
266     : m_context(context)
267 {
268     ASSERT(m_context && m_context->isContextThread());
269     m_context->registerObserver(this);
270 }
271
272 WorkerGlobalScope::Observer::~Observer()
273 {
274     if (!m_context)
275         return;
276     ASSERT(m_context->isContextThread());
277     m_context->unregisterObserver(this);
278 }
279
280 void WorkerGlobalScope::Observer::stopObserving()
281 {
282     if (!m_context)
283         return;
284     ASSERT(m_context->isContextThread());
285     m_context->unregisterObserver(this);
286     m_context = 0;
287 }
288
289 void WorkerGlobalScope::registerObserver(Observer* observer)
290 {
291     ASSERT(observer);
292     m_workerObservers.add(observer);
293 }
294
295 void WorkerGlobalScope::unregisterObserver(Observer* observer)
296 {
297     ASSERT(observer);
298     m_workerObservers.remove(observer);
299 }
300
301 void WorkerGlobalScope::notifyObserversOfStop()
302 {
303     HashSet<Observer*>::iterator iter = m_workerObservers.begin();
304     while (iter != m_workerObservers.end()) {
305         WorkerGlobalScope::Observer* observer = *iter;
306         observer->stopObserving();
307         observer->notifyStop();
308         iter = m_workerObservers.begin();
309     }
310 }
311
312 WorkerEventQueue& WorkerGlobalScope::eventQueue() const
313 {
314     return m_eventQueue;
315 }
316
317 #if ENABLE(SUBTLE_CRYPTO)
318 bool WorkerGlobalScope::wrapCryptoKey(const Vector<uint8_t>&, Vector<uint8_t>&)
319 {
320     return false;
321 }
322
323 bool WorkerGlobalScope::unwrapCryptoKey(const Vector<uint8_t>&, Vector<uint8_t>&)
324 {
325     return false;
326 }
327 #endif // ENABLE(SUBTLE_CRYPTO)
328
329 } // namespace WebCore