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
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
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.
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"
80 // TODO(toyoshim): Share implementation with WebEmbeddedWorkerImpl as much as
83 WebSharedWorkerImpl::WebSharedWorkerImpl(WebSharedWorkerClient
* client
)
85 , m_mainFrame(nullptr)
86 , m_askedToTerminate(false)
87 , m_workerInspectorProxy(WorkerInspectorProxy::create())
89 , m_pauseWorkerContextOnStart(false)
90 , m_isPausedOnStart(false)
94 WebSharedWorkerImpl::~WebSharedWorkerImpl()
97 // Detach the client before closing the view to avoid getting called back.
98 m_mainFrame
->setClient(0);
101 m_mainFrame
->close();
103 m_loaderProxy
->detachProvider(this);
106 void WebSharedWorkerImpl::terminateWorkerThread()
108 if (m_askedToTerminate
)
110 m_askedToTerminate
= true;
111 if (m_mainScriptLoader
) {
112 m_mainScriptLoader
->cancel();
113 m_mainScriptLoader
.clear();
114 m_client
->workerScriptLoadFailed();
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
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;
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.
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(),
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
)
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;
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();
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.
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
);
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
)
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
)
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.
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(
340 m_loadingDocument
->userAgent(m_url
),
341 m_mainScriptLoader
->script(),
344 contentSecurityPolicy
? contentSecurityPolicy
->headers() : nullptr,
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();
371 devtoolsAgent
->attach(hostId
);
374 void WebSharedWorkerImpl::reattachDevTools(const WebString
& hostId
, const WebString
& savedState
)
376 WebDevToolsAgent
* devtoolsAgent
= m_mainFrame
->devToolsAgent();
378 devtoolsAgent
->reattach(hostId
, savedState
);
382 void WebSharedWorkerImpl::detachDevTools()
384 WebDevToolsAgent
* devtoolsAgent
= m_mainFrame
->devToolsAgent();
386 devtoolsAgent
->detach();
389 void WebSharedWorkerImpl::dispatchDevToolsMessage(const WebString
& message
)
391 if (m_askedToTerminate
)
393 WebDevToolsAgent
* devtoolsAgent
= m_mainFrame
->devToolsAgent();
395 devtoolsAgent
->dispatchOnInspectorBackend(message
);
398 WebSharedWorker
* WebSharedWorker::create(WebSharedWorkerClient
* client
)
400 return new WebSharedWorkerImpl(client
);