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