Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / Source / web / WebSharedWorkerImpl.cpp
blobab11d3053f3fd9df420356266bd66b506f5b3740
1 /*
2 * Copyright (C) 2009 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include "config.h"
32 #include "web/WebSharedWorkerImpl.h"
34 #include "core/dom/CrossThreadTask.h"
35 #include "core/dom/Document.h"
36 #include "core/events/MessageEvent.h"
37 #include "core/html/HTMLFormElement.h"
38 #include "core/inspector/ConsoleMessage.h"
39 #include "core/inspector/InspectorInstrumentation.h"
40 #include "core/inspector/WorkerDebuggerAgent.h"
41 #include "core/inspector/WorkerInspectorController.h"
42 #include "core/loader/FrameLoadRequest.h"
43 #include "core/loader/FrameLoader.h"
44 #include "core/page/Page.h"
45 #include "core/workers/SharedWorkerGlobalScope.h"
46 #include "core/workers/SharedWorkerThread.h"
47 #include "core/workers/WorkerClients.h"
48 #include "core/workers/WorkerGlobalScope.h"
49 #include "core/workers/WorkerInspectorProxy.h"
50 #include "core/workers/WorkerLoaderProxy.h"
51 #include "core/workers/WorkerScriptLoader.h"
52 #include "core/workers/WorkerThreadStartupData.h"
53 #include "platform/RuntimeEnabledFeatures.h"
54 #include "platform/ThreadSafeFunctional.h"
55 #include "platform/heap/Handle.h"
56 #include "platform/network/ContentSecurityPolicyParsers.h"
57 #include "platform/network/ResourceResponse.h"
58 #include "platform/weborigin/KURL.h"
59 #include "platform/weborigin/SecurityOrigin.h"
60 #include "public/platform/WebFileError.h"
61 #include "public/platform/WebMessagePortChannel.h"
62 #include "public/platform/WebString.h"
63 #include "public/platform/WebURL.h"
64 #include "public/platform/WebURLRequest.h"
65 #include "public/web/WebDevToolsAgent.h"
66 #include "public/web/WebFrame.h"
67 #include "public/web/WebServiceWorkerNetworkProvider.h"
68 #include "public/web/WebSettings.h"
69 #include "public/web/WebView.h"
70 #include "public/web/WebWorkerContentSettingsClientProxy.h"
71 #include "web/LocalFileSystemClient.h"
72 #include "web/WebDataSourceImpl.h"
73 #include "web/WebLocalFrameImpl.h"
74 #include "web/WorkerContentSettingsClient.h"
75 #include "wtf/Functional.h"
76 #include "wtf/MainThread.h"
78 namespace blink {
80 // TODO(toyoshim): Share implementation with WebEmbeddedWorkerImpl as much as
81 // possible.
83 WebSharedWorkerImpl::WebSharedWorkerImpl(WebSharedWorkerClient* client)
84 : m_webView(nullptr)
85 , m_mainFrame(nullptr)
86 , m_askedToTerminate(false)
87 , m_workerInspectorProxy(WorkerInspectorProxy::create())
88 , m_client(client)
89 , m_pauseWorkerContextOnStart(false)
90 , m_isPausedOnStart(false)
94 WebSharedWorkerImpl::~WebSharedWorkerImpl()
96 ASSERT(m_webView);
97 // Detach the client before closing the view to avoid getting called back.
98 m_mainFrame->setClient(0);
100 m_webView->close();
101 m_mainFrame->close();
102 if (m_loaderProxy)
103 m_loaderProxy->detachProvider(this);
106 void WebSharedWorkerImpl::terminateWorkerThread()
108 if (m_askedToTerminate)
109 return;
110 m_askedToTerminate = true;
111 if (m_mainScriptLoader) {
112 m_mainScriptLoader->cancel();
113 m_mainScriptLoader.clear();
114 m_client->workerScriptLoadFailed();
115 delete this;
116 return;
118 if (m_workerThread)
119 m_workerThread->terminate();
120 m_workerInspectorProxy->workerThreadTerminated();
123 void WebSharedWorkerImpl::initializeLoader()
125 // Create 'shadow page'. This page is never displayed, it is used to proxy the
126 // loading requests from the worker context to the rest of WebKit and Chromium
127 // infrastructure.
128 ASSERT(!m_webView);
129 m_webView = WebView::create(0);
130 // FIXME: http://crbug.com/363843. This needs to find a better way to
131 // not create graphics layers.
132 m_webView->settings()->setAcceleratedCompositingEnabled(false);
133 // FIXME: Settings information should be passed to the Worker process from Browser process when the worker
134 // is created (similar to RenderThread::OnCreateNewView).
135 m_mainFrame = toWebLocalFrameImpl(WebLocalFrame::create(WebTreeScopeType::Document, this));
136 m_webView->setMainFrame(m_mainFrame.get());
137 m_mainFrame->setDevToolsAgentClient(this);
139 // If we were asked to pause worker context on start and wait for debugger then it is the good time to do that.
140 m_client->workerReadyForInspection();
141 if (m_pauseWorkerContextOnStart) {
142 m_isPausedOnStart = true;
143 return;
145 loadShadowPage();
148 WebApplicationCacheHost* WebSharedWorkerImpl::createApplicationCacheHost(WebLocalFrame*, WebApplicationCacheHostClient* appcacheHostClient)
150 return m_client->createApplicationCacheHost(appcacheHostClient);
153 void WebSharedWorkerImpl::loadShadowPage()
155 // Construct substitute data source for the 'shadow page'. We only need it
156 // to have same origin as the worker so the loading checks work correctly.
157 CString content("");
158 RefPtr<SharedBuffer> buffer(SharedBuffer::create(content.data(), content.length()));
159 m_mainFrame->frame()->loader().load(FrameLoadRequest(0, ResourceRequest(m_url), SubstituteData(buffer, "text/html", "UTF-8", KURL())));
162 void WebSharedWorkerImpl::willSendRequest(
163 WebLocalFrame* frame, unsigned, WebURLRequest& request,
164 const WebURLResponse& redirectResponse)
166 if (m_networkProvider)
167 m_networkProvider->willSendRequest(frame->dataSource(), request);
170 void WebSharedWorkerImpl::didFinishDocumentLoad(WebLocalFrame* frame, bool)
172 ASSERT(!m_loadingDocument);
173 ASSERT(!m_mainScriptLoader);
174 m_networkProvider = adoptPtr(m_client->createServiceWorkerNetworkProvider(frame->dataSource()));
175 m_mainScriptLoader = WorkerScriptLoader::create();
176 m_mainScriptLoader->setRequestContext(WebURLRequest::RequestContextSharedWorker);
177 m_loadingDocument = toWebLocalFrameImpl(frame)->frame()->document();
178 m_mainScriptLoader->loadAsynchronously(
179 *m_loadingDocument.get(),
180 m_url,
181 DenyCrossOriginRequests,
182 bind(&WebSharedWorkerImpl::didReceiveScriptLoaderResponse, this),
183 bind(&WebSharedWorkerImpl::onScriptLoaderFinished, this));
184 // Do nothing here since onScriptLoaderFinished() might have been already
185 // invoked and |this| might have been deleted at this point.
188 bool WebSharedWorkerImpl::isControlledByServiceWorker(WebDataSource& dataSource)
190 return m_networkProvider && m_networkProvider->isControlledByServiceWorker(dataSource);
193 int64_t WebSharedWorkerImpl::serviceWorkerID(WebDataSource& dataSource)
195 if (!m_networkProvider)
196 return -1;
197 return m_networkProvider->serviceWorkerID(dataSource);
200 void WebSharedWorkerImpl::sendProtocolMessage(int callId, const WebString& message, const WebString& state)
202 m_client->sendDevToolsMessage(callId, message, state);
205 void WebSharedWorkerImpl::resumeStartup()
207 bool isPausedOnStart = m_isPausedOnStart;
208 m_isPausedOnStart = false;
209 if (isPausedOnStart)
210 loadShadowPage();
213 // WorkerReportingProxy --------------------------------------------------------
215 void WebSharedWorkerImpl::reportException(const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL, int exceptionId)
217 // Not suppported in SharedWorker.
220 void WebSharedWorkerImpl::reportConsoleMessage(PassRefPtrWillBeRawPtr<ConsoleMessage>)
222 // Not supported in SharedWorker.
225 void WebSharedWorkerImpl::postMessageToPageInspector(const String& message)
227 m_mainFrame->frame()->document()->postInspectorTask(FROM_HERE, createCrossThreadTask(&WebSharedWorkerImpl::postMessageToPageInspectorOnMainThread, this, message));
230 void WebSharedWorkerImpl::postMessageToPageInspectorOnMainThread(const String& message)
232 WorkerInspectorProxy::PageInspector* pageInspector = m_workerInspectorProxy->pageInspector();
233 if (!pageInspector)
234 return;
235 pageInspector->dispatchMessageFromWorker(message);
239 void WebSharedWorkerImpl::workerGlobalScopeClosed()
241 Platform::current()->mainThread()->taskRunner()->postTask(FROM_HERE, threadSafeBind(&WebSharedWorkerImpl::workerGlobalScopeClosedOnMainThread, AllowCrossThreadAccess(this)));
244 void WebSharedWorkerImpl::workerGlobalScopeClosedOnMainThread()
246 m_client->workerContextClosed();
248 terminateWorkerThread();
251 void WebSharedWorkerImpl::workerGlobalScopeStarted(WorkerGlobalScope*)
255 void WebSharedWorkerImpl::workerThreadTerminated()
257 Platform::current()->mainThread()->taskRunner()->postTask(FROM_HERE, threadSafeBind(&WebSharedWorkerImpl::workerThreadTerminatedOnMainThread, AllowCrossThreadAccess(this)));
260 void WebSharedWorkerImpl::workerThreadTerminatedOnMainThread()
262 m_client->workerContextDestroyed();
263 // The lifetime of this proxy is controlled by the worker context.
264 delete this;
267 // WorkerLoaderProxyProvider -----------------------------------------------------------
269 void WebSharedWorkerImpl::postTaskToLoader(PassOwnPtr<ExecutionContextTask> task)
271 m_mainFrame->frame()->document()->postTask(FROM_HERE, task);
274 bool WebSharedWorkerImpl::postTaskToWorkerGlobalScope(PassOwnPtr<ExecutionContextTask> task)
276 m_workerThread->postTask(FROM_HERE, task);
277 return true;
280 void WebSharedWorkerImpl::connect(WebMessagePortChannel* webChannel)
282 workerThread()->postTask(
283 FROM_HERE, createCrossThreadTask(&connectTask, adoptPtr(webChannel)));
286 void WebSharedWorkerImpl::connectTask(PassOwnPtr<WebMessagePortChannel> channel, ExecutionContext* context)
288 // Wrap the passed-in channel in a MessagePort, and send it off via a connect event.
289 MessagePort* port = MessagePort::create(*context);
290 port->entangle(channel);
291 WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(context);
292 ASSERT_WITH_SECURITY_IMPLICATION(workerGlobalScope->isSharedWorkerGlobalScope());
293 workerGlobalScope->dispatchEvent(createConnectEvent(port));
296 void WebSharedWorkerImpl::startWorkerContext(const WebURL& url, const WebString& name, const WebString& contentSecurityPolicy, WebContentSecurityPolicyType policyType)
298 m_url = url;
299 m_name = name;
300 initializeLoader();
303 void WebSharedWorkerImpl::didReceiveScriptLoaderResponse()
305 InspectorInstrumentation::didReceiveScriptResponse(m_loadingDocument.get(), m_mainScriptLoader->identifier());
306 m_client->selectAppCacheID(m_mainScriptLoader->appCacheID());
309 void WebSharedWorkerImpl::onScriptLoaderFinished()
311 ASSERT(m_loadingDocument);
312 ASSERT(m_mainScriptLoader);
313 if (m_askedToTerminate)
314 return;
315 if (m_mainScriptLoader->failed()) {
316 m_mainScriptLoader->cancel();
317 m_client->workerScriptLoadFailed();
319 // The SharedWorker was unable to load the initial script, so
320 // shut it down right here.
321 delete this;
322 return;
325 Document* document = m_mainFrame->frame()->document();
326 WorkerThreadStartMode startMode = DontPauseWorkerGlobalScopeOnStart;
327 if (InspectorInstrumentation::shouldPauseDedicatedWorkerOnStart(document))
328 startMode = PauseWorkerGlobalScopeOnStart;
330 // FIXME: this document's origin is pristine and without any extra privileges. (crbug.com/254993)
331 SecurityOrigin* starterOrigin = document->securityOrigin();
333 OwnPtrWillBeRawPtr<WorkerClients> workerClients = WorkerClients::create();
334 provideLocalFileSystemToWorker(workerClients.get(), LocalFileSystemClient::create());
335 WebSecurityOrigin webSecurityOrigin(m_loadingDocument->securityOrigin());
336 provideContentSettingsClientToWorker(workerClients.get(), adoptPtr(m_client->createWorkerContentSettingsClientProxy(webSecurityOrigin)));
337 RefPtrWillBeRawPtr<ContentSecurityPolicy> contentSecurityPolicy = m_mainScriptLoader->releaseContentSecurityPolicy();
338 OwnPtr<WorkerThreadStartupData> startupData = WorkerThreadStartupData::create(
339 m_url,
340 m_loadingDocument->userAgent(m_url),
341 m_mainScriptLoader->script(),
342 nullptr,
343 startMode,
344 contentSecurityPolicy ? contentSecurityPolicy->headers() : nullptr,
345 starterOrigin,
346 workerClients.release());
347 m_loaderProxy = WorkerLoaderProxy::create(this);
348 setWorkerThread(SharedWorkerThread::create(m_name, m_loaderProxy, *this));
349 InspectorInstrumentation::scriptImported(m_loadingDocument.get(), m_mainScriptLoader->identifier(), m_mainScriptLoader->script());
350 m_mainScriptLoader.clear();
352 workerThread()->start(startupData.release());
353 m_workerInspectorProxy->workerThreadCreated(m_loadingDocument.get(), workerThread(), m_url);
354 m_client->workerScriptLoaded();
357 void WebSharedWorkerImpl::terminateWorkerContext()
359 terminateWorkerThread();
362 void WebSharedWorkerImpl::pauseWorkerContextOnStart()
364 m_pauseWorkerContextOnStart = true;
367 void WebSharedWorkerImpl::attachDevTools(const WebString& hostId)
369 WebDevToolsAgent* devtoolsAgent = m_mainFrame->devToolsAgent();
370 if (devtoolsAgent)
371 devtoolsAgent->attach(hostId);
374 void WebSharedWorkerImpl::reattachDevTools(const WebString& hostId, const WebString& savedState)
376 WebDevToolsAgent* devtoolsAgent = m_mainFrame->devToolsAgent();
377 if (devtoolsAgent)
378 devtoolsAgent->reattach(hostId, savedState);
379 resumeStartup();
382 void WebSharedWorkerImpl::detachDevTools()
384 WebDevToolsAgent* devtoolsAgent = m_mainFrame->devToolsAgent();
385 if (devtoolsAgent)
386 devtoolsAgent->detach();
389 void WebSharedWorkerImpl::dispatchDevToolsMessage(const WebString& message)
391 if (m_askedToTerminate)
392 return;
393 WebDevToolsAgent* devtoolsAgent = m_mainFrame->devToolsAgent();
394 if (devtoolsAgent)
395 devtoolsAgent->dispatchOnInspectorBackend(message);
398 WebSharedWorker* WebSharedWorker::create(WebSharedWorkerClient* client)
400 return new WebSharedWorkerImpl(client);
403 } // namespace blink