1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/renderer/shared_worker/embedded_shared_worker_stub.h"
7 #include "base/thread_task_runner_handle.h"
8 #include "content/child/appcache/appcache_dispatcher.h"
9 #include "content/child/appcache/web_application_cache_host_impl.h"
10 #include "content/child/request_extra_data.h"
11 #include "content/child/scoped_child_process_reference.h"
12 #include "content/child/service_worker/service_worker_handle_reference.h"
13 #include "content/child/service_worker/service_worker_network_provider.h"
14 #include "content/child/service_worker/service_worker_provider_context.h"
15 #include "content/child/shared_worker_devtools_agent.h"
16 #include "content/child/webmessageportchannel_impl.h"
17 #include "content/common/worker_messages.h"
18 #include "content/renderer/render_thread_impl.h"
19 #include "content/renderer/shared_worker/embedded_shared_worker_content_settings_client_proxy.h"
20 #include "ipc/ipc_message_macros.h"
21 #include "third_party/WebKit/public/platform/WebURLRequest.h"
22 #include "third_party/WebKit/public/web/WebDataSource.h"
23 #include "third_party/WebKit/public/web/WebSecurityOrigin.h"
24 #include "third_party/WebKit/public/web/WebSharedWorker.h"
25 #include "third_party/WebKit/public/web/WebSharedWorkerClient.h"
26 #include "third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerNetworkProvider.h"
32 class SharedWorkerWebApplicationCacheHostImpl
33 : public WebApplicationCacheHostImpl
{
35 SharedWorkerWebApplicationCacheHostImpl(
36 blink::WebApplicationCacheHostClient
* client
)
37 : WebApplicationCacheHostImpl(client
,
38 RenderThreadImpl::current()
39 ->appcache_dispatcher()
42 // Main resource loading is different for workers. The main resource is
43 // loaded by the worker using WorkerScriptLoader.
44 // These overrides are stubbed out.
45 virtual void willStartMainResourceRequest(
46 blink::WebURLRequest
&,
47 const blink::WebApplicationCacheHost
*) {}
48 virtual void didReceiveResponseForMainResource(const blink::WebURLResponse
&) {
50 virtual void didReceiveDataForMainResource(const char* data
, unsigned len
) {}
51 virtual void didFinishLoadingMainResource(bool success
) {}
53 // Cache selection is also different for workers. We know at construction
54 // time what cache to select and do so then.
55 // These overrides are stubbed out.
56 virtual void selectCacheWithoutManifest() {}
57 virtual bool selectCacheWithManifest(const blink::WebURL
& manifestURL
) {
62 // We store an instance of this class in the "extra data" of the WebDataSource
63 // and attach a ServiceWorkerNetworkProvider to it as base::UserData.
64 // (see createServiceWorkerNetworkProvider).
65 class DataSourceExtraData
66 : public blink::WebDataSource::ExtraData
,
67 public base::SupportsUserData
{
69 DataSourceExtraData() {}
70 virtual ~DataSourceExtraData() {}
73 // Called on the main thread only and blink owns it.
74 class WebServiceWorkerNetworkProviderImpl
75 : public blink::WebServiceWorkerNetworkProvider
{
77 // Blink calls this method for each request starting with the main script,
78 // we tag them with the provider id.
79 virtual void willSendRequest(
80 blink::WebDataSource
* data_source
,
81 blink::WebURLRequest
& request
) {
82 ServiceWorkerNetworkProvider
* provider
=
83 GetNetworkProviderFromDataSource(data_source
);
84 scoped_ptr
<RequestExtraData
> extra_data(new RequestExtraData
);
85 extra_data
->set_service_worker_provider_id(provider
->provider_id());
86 request
.setExtraData(extra_data
.release());
87 // Explicitly set the SkipServiceWorker flag for subresources here if the
88 // renderer process hasn't received SetControllerServiceWorker message.
89 if (request
.requestContext() !=
90 blink::WebURLRequest::RequestContextSharedWorker
&&
91 !provider
->IsControlledByServiceWorker()) {
92 request
.setSkipServiceWorker(true);
96 virtual bool isControlledByServiceWorker(
97 blink::WebDataSource
& data_source
) {
98 ServiceWorkerNetworkProvider
* provider
=
99 GetNetworkProviderFromDataSource(&data_source
);
100 return provider
->IsControlledByServiceWorker();
103 virtual int64_t serviceWorkerID(
104 blink::WebDataSource
& data_source
) {
105 ServiceWorkerNetworkProvider
* provider
=
106 GetNetworkProviderFromDataSource(&data_source
);
107 if (provider
->context()->controller())
108 return provider
->context()->controller()->version_id();
109 return kInvalidServiceWorkerVersionId
;
113 ServiceWorkerNetworkProvider
* GetNetworkProviderFromDataSource(
114 const blink::WebDataSource
* data_source
) {
115 return ServiceWorkerNetworkProvider::FromDocumentState(
116 static_cast<DataSourceExtraData
*>(data_source
->extraData()));
122 EmbeddedSharedWorkerStub::EmbeddedSharedWorkerStub(
124 const base::string16
& name
,
125 const base::string16
& content_security_policy
,
126 blink::WebContentSecurityPolicyType security_policy_type
,
129 : route_id_(route_id
),
132 RenderThreadImpl::current()->AddEmbeddedWorkerRoute(route_id_
, this);
133 impl_
= blink::WebSharedWorker::create(this);
134 if (pause_on_start
) {
135 // Pause worker context when it starts and wait until either DevTools client
136 // is attached or explicit resume notification is received.
137 impl_
->pauseWorkerContextOnStart();
139 worker_devtools_agent_
.reset(
140 new SharedWorkerDevToolsAgent(route_id
, impl_
));
141 impl_
->startWorkerContext(url
, name_
,
142 content_security_policy
, security_policy_type
);
145 EmbeddedSharedWorkerStub::~EmbeddedSharedWorkerStub() {
146 RenderThreadImpl::current()->RemoveEmbeddedWorkerRoute(route_id_
);
150 bool EmbeddedSharedWorkerStub::OnMessageReceived(
151 const IPC::Message
& message
) {
152 if (worker_devtools_agent_
->OnMessageReceived(message
))
155 IPC_BEGIN_MESSAGE_MAP(EmbeddedSharedWorkerStub
, message
)
156 IPC_MESSAGE_HANDLER(WorkerMsg_TerminateWorkerContext
,
157 OnTerminateWorkerContext
)
158 IPC_MESSAGE_HANDLER(WorkerMsg_Connect
, OnConnect
)
159 IPC_MESSAGE_UNHANDLED(handled
= false)
160 IPC_END_MESSAGE_MAP()
164 void EmbeddedSharedWorkerStub::OnChannelError() {
165 OnTerminateWorkerContext();
168 void EmbeddedSharedWorkerStub::workerReadyForInspection() {
169 Send(new WorkerHostMsg_WorkerReadyForInspection(route_id_
));
172 void EmbeddedSharedWorkerStub::workerScriptLoaded() {
173 Send(new WorkerHostMsg_WorkerScriptLoaded(route_id_
));
175 // Process any pending connections.
176 for (PendingChannelList::const_iterator iter
= pending_channels_
.begin();
177 iter
!= pending_channels_
.end();
179 ConnectToChannel(*iter
);
181 pending_channels_
.clear();
184 void EmbeddedSharedWorkerStub::workerScriptLoadFailed() {
185 Send(new WorkerHostMsg_WorkerScriptLoadFailed(route_id_
));
186 for (PendingChannelList::const_iterator iter
= pending_channels_
.begin();
187 iter
!= pending_channels_
.end();
189 blink::WebMessagePortChannel
* channel
= *iter
;
192 pending_channels_
.clear();
196 void EmbeddedSharedWorkerStub::workerContextClosed() {
197 Send(new WorkerHostMsg_WorkerContextClosed(route_id_
));
200 void EmbeddedSharedWorkerStub::workerContextDestroyed() {
201 Send(new WorkerHostMsg_WorkerContextDestroyed(route_id_
));
205 void EmbeddedSharedWorkerStub::selectAppCacheID(long long app_cache_id
) {
206 if (app_cache_host_
) {
207 // app_cache_host_ could become stale as it's owned by blink's
208 // DocumentLoader. This method is assumed to be called while it's valid.
209 app_cache_host_
->backend()->SelectCacheForSharedWorker(
210 app_cache_host_
->host_id(), app_cache_id
);
214 blink::WebNotificationPresenter
*
215 EmbeddedSharedWorkerStub::notificationPresenter() {
216 // TODO(horo): delete this method if we have no plan to implement this.
221 blink::WebApplicationCacheHost
*
222 EmbeddedSharedWorkerStub::createApplicationCacheHost(
223 blink::WebApplicationCacheHostClient
* client
) {
224 app_cache_host_
= new SharedWorkerWebApplicationCacheHostImpl(client
);
225 return app_cache_host_
;
228 blink::WebWorkerContentSettingsClientProxy
*
229 EmbeddedSharedWorkerStub::createWorkerContentSettingsClientProxy(
230 const blink::WebSecurityOrigin
& origin
) {
231 return new EmbeddedSharedWorkerContentSettingsClientProxy(
232 GURL(origin
.toString()),
235 ChildThreadImpl::current()->thread_safe_sender());
238 blink::WebServiceWorkerNetworkProvider
*
239 EmbeddedSharedWorkerStub::createServiceWorkerNetworkProvider(
240 blink::WebDataSource
* data_source
) {
241 // Create a content::ServiceWorkerNetworkProvider for this data source so
242 // we can observe its requests.
243 scoped_ptr
<ServiceWorkerNetworkProvider
> provider(
244 new ServiceWorkerNetworkProvider(
245 route_id_
, SERVICE_WORKER_PROVIDER_FOR_SHARED_WORKER
));
247 // The provider is kept around for the lifetime of the DataSource
248 // and ownership is transferred to the DataSource.
249 DataSourceExtraData
* extra_data
= new DataSourceExtraData();
250 data_source
->setExtraData(extra_data
);
251 ServiceWorkerNetworkProvider::AttachToDocumentState(
252 extra_data
, provider
.Pass());
254 // Blink is responsible for deleting the returned object.
255 return new WebServiceWorkerNetworkProviderImpl();
258 void EmbeddedSharedWorkerStub::sendDevToolsMessage(
260 const blink::WebString
& message
,
261 const blink::WebString
& state
) {
262 worker_devtools_agent_
->SendDevToolsMessage(call_id
, message
, state
);
265 void EmbeddedSharedWorkerStub::Shutdown() {
266 // WebSharedWorker must be already deleted in the blink side
267 // when this is called.
272 bool EmbeddedSharedWorkerStub::Send(IPC::Message
* message
) {
273 return RenderThreadImpl::current()->Send(message
);
276 void EmbeddedSharedWorkerStub::ConnectToChannel(
277 WebMessagePortChannelImpl
* channel
) {
278 impl_
->connect(channel
);
280 new WorkerHostMsg_WorkerConnected(channel
->message_port_id(), route_id_
));
283 void EmbeddedSharedWorkerStub::OnConnect(int sent_message_port_id
,
285 TransferredMessagePort port
;
286 port
.id
= sent_message_port_id
;
287 WebMessagePortChannelImpl
* channel
= new WebMessagePortChannelImpl(
288 routing_id
, port
, base::ThreadTaskRunnerHandle::Get().get());
290 ConnectToChannel(channel
);
292 // If two documents try to load a SharedWorker at the same time, the
293 // WorkerMsg_Connect for one of the documents can come in before the
294 // worker is started. Just queue up the connect and deliver it once the
296 pending_channels_
.push_back(channel
);
300 void EmbeddedSharedWorkerStub::OnTerminateWorkerContext() {
301 // After this we wouldn't get any IPC for this stub.
303 impl_
->terminateWorkerContext();
306 } // namespace content