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