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