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