Re-enable blink_perf.canvas on Windows
[chromium-blink-merge.git] / content / renderer / service_worker / embedded_worker_context_client.cc
blobc393502617e0a35f5c06bb8e86131c559e22df19
1 // Copyright 2013 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/service_worker/embedded_worker_context_client.h"
7 #include <map>
8 #include <string>
10 #include "base/lazy_instance.h"
11 #include "base/message_loop/message_loop_proxy.h"
12 #include "base/pickle.h"
13 #include "base/strings/string16.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/thread_task_runner_handle.h"
16 #include "base/threading/thread_local.h"
17 #include "base/trace_event/trace_event.h"
18 #include "content/child/request_extra_data.h"
19 #include "content/child/service_worker/service_worker_dispatcher.h"
20 #include "content/child/service_worker/service_worker_network_provider.h"
21 #include "content/child/service_worker/service_worker_provider_context.h"
22 #include "content/child/service_worker/service_worker_registration_handle_reference.h"
23 #include "content/child/service_worker/web_service_worker_impl.h"
24 #include "content/child/service_worker/web_service_worker_provider_impl.h"
25 #include "content/child/service_worker/web_service_worker_registration_impl.h"
26 #include "content/child/thread_safe_sender.h"
27 #include "content/child/worker_task_runner.h"
28 #include "content/common/devtools_messages.h"
29 #include "content/common/service_worker/embedded_worker_messages.h"
30 #include "content/common/service_worker/service_worker_types.h"
31 #include "content/public/renderer/document_state.h"
32 #include "content/renderer/devtools/devtools_agent.h"
33 #include "content/renderer/render_thread_impl.h"
34 #include "content/renderer/service_worker/embedded_worker_dispatcher.h"
35 #include "content/renderer/service_worker/service_worker_script_context.h"
36 #include "content/renderer/service_worker/service_worker_type_util.h"
37 #include "ipc/ipc_message_macros.h"
38 #include "third_party/WebKit/public/platform/WebServiceWorkerResponse.h"
39 #include "third_party/WebKit/public/platform/WebString.h"
40 #include "third_party/WebKit/public/web/WebDataSource.h"
41 #include "third_party/WebKit/public/web/WebServiceWorkerNetworkProvider.h"
43 namespace content {
45 namespace {
47 // For now client must be a per-thread instance.
48 // TODO(kinuko): This needs to be refactored when we start using thread pool
49 // or having multiple clients per one thread.
50 base::LazyInstance<base::ThreadLocalPointer<EmbeddedWorkerContextClient> >::
51 Leaky g_worker_client_tls = LAZY_INSTANCE_INITIALIZER;
53 void CallWorkerContextDestroyedOnMainThread(int embedded_worker_id) {
54 if (!RenderThreadImpl::current() ||
55 !RenderThreadImpl::current()->embedded_worker_dispatcher())
56 return;
57 RenderThreadImpl::current()->embedded_worker_dispatcher()->
58 WorkerContextDestroyed(embedded_worker_id);
61 // We store an instance of this class in the "extra data" of the WebDataSource
62 // and attach a ServiceWorkerNetworkProvider to it as base::UserData.
63 // (see createServiceWorkerNetworkProvider).
64 class DataSourceExtraData
65 : public blink::WebDataSource::ExtraData,
66 public base::SupportsUserData {
67 public:
68 DataSourceExtraData() {}
69 virtual ~DataSourceExtraData() {}
72 // Called on the main thread only and blink owns it.
73 class WebServiceWorkerNetworkProviderImpl
74 : public blink::WebServiceWorkerNetworkProvider {
75 public:
76 // Blink calls this method for each request starting with the main script,
77 // we tag them with the provider id.
78 virtual void willSendRequest(
79 blink::WebDataSource* data_source,
80 blink::WebURLRequest& request) {
81 ServiceWorkerNetworkProvider* provider =
82 ServiceWorkerNetworkProvider::FromDocumentState(
83 static_cast<DataSourceExtraData*>(data_source->extraData()));
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());
90 } // namespace
92 EmbeddedWorkerContextClient*
93 EmbeddedWorkerContextClient::ThreadSpecificInstance() {
94 return g_worker_client_tls.Pointer()->Get();
97 EmbeddedWorkerContextClient::EmbeddedWorkerContextClient(
98 int embedded_worker_id,
99 int64 service_worker_version_id,
100 const GURL& service_worker_scope,
101 const GURL& script_url,
102 int worker_devtools_agent_route_id)
103 : embedded_worker_id_(embedded_worker_id),
104 service_worker_version_id_(service_worker_version_id),
105 service_worker_scope_(service_worker_scope),
106 script_url_(script_url),
107 worker_devtools_agent_route_id_(worker_devtools_agent_route_id),
108 sender_(ChildThreadImpl::current()->thread_safe_sender()),
109 main_thread_task_runner_(RenderThreadImpl::current()->GetTaskRunner()),
110 weak_factory_(this) {
111 TRACE_EVENT_ASYNC_BEGIN0("ServiceWorker",
112 "EmbeddedWorkerContextClient::StartingWorkerContext",
113 this);
114 TRACE_EVENT_ASYNC_STEP_INTO0(
115 "ServiceWorker",
116 "EmbeddedWorkerContextClient::StartingWorkerContext",
117 this,
118 "PrepareWorker");
121 EmbeddedWorkerContextClient::~EmbeddedWorkerContextClient() {
124 bool EmbeddedWorkerContextClient::OnMessageReceived(
125 const IPC::Message& msg) {
126 bool handled = true;
127 IPC_BEGIN_MESSAGE_MAP(EmbeddedWorkerContextClient, msg)
128 IPC_MESSAGE_HANDLER(EmbeddedWorkerContextMsg_MessageToWorker,
129 OnMessageToWorker)
130 IPC_MESSAGE_UNHANDLED(handled = false)
131 IPC_END_MESSAGE_MAP()
132 return handled;
135 void EmbeddedWorkerContextClient::Send(IPC::Message* message) {
136 sender_->Send(message);
139 blink::WebURL EmbeddedWorkerContextClient::scope() const {
140 return service_worker_scope_;
143 void EmbeddedWorkerContextClient::didPauseAfterDownload() {
144 Send(new EmbeddedWorkerHostMsg_DidPauseAfterDownload(embedded_worker_id_));
147 void EmbeddedWorkerContextClient::getClients(
148 const blink::WebServiceWorkerClientQueryOptions& options,
149 blink::WebServiceWorkerClientsCallbacks* callbacks) {
150 DCHECK(script_context_);
151 script_context_->GetClients(options, callbacks);
154 void EmbeddedWorkerContextClient::openWindow(
155 const blink::WebURL& url,
156 blink::WebServiceWorkerClientCallbacks* callbacks) {
157 DCHECK(script_context_);
158 script_context_->OpenWindow(url, callbacks);
161 void EmbeddedWorkerContextClient::setCachedMetadata(const blink::WebURL& url,
162 const char* data,
163 size_t size) {
164 DCHECK(script_context_);
165 script_context_->SetCachedMetadata(url, data, size);
168 void EmbeddedWorkerContextClient::clearCachedMetadata(
169 const blink::WebURL& url) {
170 DCHECK(script_context_);
171 script_context_->ClearCachedMetadata(url);
174 void EmbeddedWorkerContextClient::workerReadyForInspection() {
175 Send(new EmbeddedWorkerHostMsg_WorkerReadyForInspection(embedded_worker_id_));
178 void EmbeddedWorkerContextClient::workerContextFailedToStart() {
179 DCHECK(main_thread_task_runner_->RunsTasksOnCurrentThread());
180 DCHECK(!script_context_);
182 Send(new EmbeddedWorkerHostMsg_WorkerScriptLoadFailed(embedded_worker_id_));
184 RenderThreadImpl::current()->embedded_worker_dispatcher()->
185 WorkerContextDestroyed(embedded_worker_id_);
188 void EmbeddedWorkerContextClient::workerContextStarted(
189 blink::WebServiceWorkerContextProxy* proxy) {
190 DCHECK(!worker_task_runner_.get());
191 DCHECK_NE(0, WorkerTaskRunner::Instance()->CurrentWorkerId());
192 worker_task_runner_ = base::ThreadTaskRunnerHandle::Get();
193 // g_worker_client_tls.Pointer()->Get() could return NULL if this context
194 // gets deleted before workerContextStarted() is called.
195 DCHECK(g_worker_client_tls.Pointer()->Get() == NULL);
196 DCHECK(!script_context_);
197 g_worker_client_tls.Pointer()->Set(this);
198 script_context_.reset(new ServiceWorkerScriptContext(this, proxy));
200 SetRegistrationInServiceWorkerGlobalScope();
202 Send(new EmbeddedWorkerHostMsg_WorkerScriptLoaded(
203 embedded_worker_id_,
204 WorkerTaskRunner::Instance()->CurrentWorkerId(),
205 provider_context_->provider_id()));
207 TRACE_EVENT_ASYNC_STEP_INTO0(
208 "ServiceWorker",
209 "EmbeddedWorkerContextClient::StartingWorkerContext",
210 this,
211 "ExecuteScript");
214 void EmbeddedWorkerContextClient::didEvaluateWorkerScript(bool success) {
215 Send(new EmbeddedWorkerHostMsg_WorkerScriptEvaluated(
216 embedded_worker_id_, success));
218 // Schedule a task to send back WorkerStarted asynchronously,
219 // so that at the time we send it we can be sure that the
220 // worker run loop has been started.
221 worker_task_runner_->PostTask(
222 FROM_HERE, base::Bind(&EmbeddedWorkerContextClient::SendWorkerStarted,
223 weak_factory_.GetWeakPtr()));
226 void EmbeddedWorkerContextClient::willDestroyWorkerContext() {
227 // At this point OnWorkerRunLoopStopped is already called, so
228 // worker_task_runner_->RunsTasksOnCurrentThread() returns false
229 // (while we're still on the worker thread).
230 script_context_.reset();
232 // This also lets the message filter stop dispatching messages to
233 // this client.
234 g_worker_client_tls.Pointer()->Set(NULL);
237 void EmbeddedWorkerContextClient::workerContextDestroyed() {
238 DCHECK(g_worker_client_tls.Pointer()->Get() == NULL);
240 // Now we should be able to free the WebEmbeddedWorker container on the
241 // main thread.
242 main_thread_task_runner_->PostTask(
243 FROM_HERE,
244 base::Bind(&CallWorkerContextDestroyedOnMainThread,
245 embedded_worker_id_));
248 void EmbeddedWorkerContextClient::reportException(
249 const blink::WebString& error_message,
250 int line_number,
251 int column_number,
252 const blink::WebString& source_url) {
253 Send(new EmbeddedWorkerHostMsg_ReportException(
254 embedded_worker_id_, error_message, line_number,
255 column_number, GURL(source_url)));
258 void EmbeddedWorkerContextClient::reportConsoleMessage(
259 int source,
260 int level,
261 const blink::WebString& message,
262 int line_number,
263 const blink::WebString& source_url) {
264 EmbeddedWorkerHostMsg_ReportConsoleMessage_Params params;
265 params.source_identifier = source;
266 params.message_level = level;
267 params.message = message;
268 params.line_number = line_number;
269 params.source_url = GURL(source_url);
271 Send(new EmbeddedWorkerHostMsg_ReportConsoleMessage(
272 embedded_worker_id_, params));
275 void EmbeddedWorkerContextClient::sendDevToolsMessage(
276 int call_id,
277 const blink::WebString& message,
278 const blink::WebString& state_cookie) {
279 DevToolsAgent::SendChunkedProtocolMessage(
280 sender_.get(), worker_devtools_agent_route_id_,
281 call_id, message.utf8(), state_cookie.utf8());
284 void EmbeddedWorkerContextClient::didHandleActivateEvent(
285 int request_id,
286 blink::WebServiceWorkerEventResult result) {
287 DCHECK(script_context_);
288 script_context_->DidHandleActivateEvent(request_id, result);
291 void EmbeddedWorkerContextClient::didHandleInstallEvent(
292 int request_id,
293 blink::WebServiceWorkerEventResult result) {
294 DCHECK(script_context_);
295 script_context_->DidHandleInstallEvent(request_id, result);
298 void EmbeddedWorkerContextClient::didHandleFetchEvent(int request_id) {
299 DCHECK(script_context_);
300 script_context_->DidHandleFetchEvent(
301 request_id,
302 SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK,
303 ServiceWorkerResponse());
306 void EmbeddedWorkerContextClient::didHandleFetchEvent(
307 int request_id,
308 const blink::WebServiceWorkerResponse& web_response) {
309 DCHECK(script_context_);
310 ServiceWorkerHeaderMap headers;
311 GetServiceWorkerHeaderMapFromWebResponse(web_response, &headers);
312 ServiceWorkerResponse response(web_response.url(),
313 web_response.status(),
314 web_response.statusText().utf8(),
315 web_response.responseType(),
316 headers,
317 web_response.blobUUID().utf8(),
318 web_response.blobSize(),
319 web_response.streamURL());
320 script_context_->DidHandleFetchEvent(
321 request_id, SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE, response);
324 void EmbeddedWorkerContextClient::didHandleNotificationClickEvent(
325 int request_id,
326 blink::WebServiceWorkerEventResult result) {
327 DCHECK(script_context_);
328 script_context_->DidHandleNotificationClickEvent(request_id, result);
331 void EmbeddedWorkerContextClient::didHandlePushEvent(
332 int request_id,
333 blink::WebServiceWorkerEventResult result) {
334 DCHECK(script_context_);
335 script_context_->DidHandlePushEvent(request_id, result);
338 void EmbeddedWorkerContextClient::didHandleSyncEvent(int request_id) {
339 DCHECK(script_context_);
340 script_context_->DidHandleSyncEvent(request_id);
343 void EmbeddedWorkerContextClient::didHandleCrossOriginConnectEvent(
344 int request_id,
345 bool accept_connection) {
346 DCHECK(script_context_);
347 script_context_->DidHandleCrossOriginConnectEvent(request_id,
348 accept_connection);
351 blink::WebServiceWorkerNetworkProvider*
352 EmbeddedWorkerContextClient::createServiceWorkerNetworkProvider(
353 blink::WebDataSource* data_source) {
354 DCHECK(main_thread_task_runner_->RunsTasksOnCurrentThread());
356 // Create a content::ServiceWorkerNetworkProvider for this data source so
357 // we can observe its requests.
358 scoped_ptr<ServiceWorkerNetworkProvider> provider(
359 new ServiceWorkerNetworkProvider(
360 MSG_ROUTING_NONE, SERVICE_WORKER_PROVIDER_FOR_CONTROLLER));
361 provider_context_ = provider->context();
363 // Tell the network provider about which version to load.
364 provider->SetServiceWorkerVersionId(service_worker_version_id_);
366 // The provider is kept around for the lifetime of the DataSource
367 // and ownership is transferred to the DataSource.
368 DataSourceExtraData* extra_data = new DataSourceExtraData();
369 data_source->setExtraData(extra_data);
370 ServiceWorkerNetworkProvider::AttachToDocumentState(
371 extra_data, provider.Pass());
373 // Blink is responsible for deleting the returned object.
374 return new WebServiceWorkerNetworkProviderImpl();
377 blink::WebServiceWorkerProvider*
378 EmbeddedWorkerContextClient::createServiceWorkerProvider() {
379 DCHECK(main_thread_task_runner_->RunsTasksOnCurrentThread());
380 DCHECK(provider_context_);
382 // Blink is responsible for deleting the returned object.
383 return new WebServiceWorkerProviderImpl(
384 thread_safe_sender(), provider_context_.get());
387 void EmbeddedWorkerContextClient::postMessageToClient(
388 const blink::WebString& uuid,
389 const blink::WebString& message,
390 blink::WebMessagePortChannelArray* channels) {
391 DCHECK(script_context_);
392 script_context_->PostMessageToClient(
393 uuid, message, make_scoped_ptr(channels));
396 void EmbeddedWorkerContextClient::postMessageToCrossOriginClient(
397 const blink::WebCrossOriginServiceWorkerClient& client,
398 const blink::WebString& message,
399 blink::WebMessagePortChannelArray* channels) {
400 DCHECK(script_context_);
401 script_context_->PostCrossOriginMessageToClient(client, message,
402 make_scoped_ptr(channels));
405 void EmbeddedWorkerContextClient::focus(
406 const blink::WebString& uuid,
407 blink::WebServiceWorkerClientCallbacks* callback) {
408 DCHECK(script_context_);
409 script_context_->FocusClient(uuid, callback);
412 void EmbeddedWorkerContextClient::skipWaiting(
413 blink::WebServiceWorkerSkipWaitingCallbacks* callbacks) {
414 DCHECK(script_context_);
415 script_context_->SkipWaiting(callbacks);
418 void EmbeddedWorkerContextClient::claim(
419 blink::WebServiceWorkerClientsClaimCallbacks* callbacks) {
420 DCHECK(script_context_);
421 script_context_->ClaimClients(callbacks);
424 void EmbeddedWorkerContextClient::OnMessageToWorker(
425 int thread_id,
426 int embedded_worker_id,
427 const IPC::Message& message) {
428 if (!script_context_)
429 return;
430 DCHECK_EQ(embedded_worker_id_, embedded_worker_id);
431 script_context_->OnMessageReceived(message);
434 void EmbeddedWorkerContextClient::SendWorkerStarted() {
435 DCHECK(worker_task_runner_->RunsTasksOnCurrentThread());
436 TRACE_EVENT_ASYNC_END0("ServiceWorker",
437 "EmbeddedWorkerContextClient::StartingWorkerContext",
438 this);
439 Send(new EmbeddedWorkerHostMsg_WorkerStarted(embedded_worker_id_));
442 void EmbeddedWorkerContextClient::SetRegistrationInServiceWorkerGlobalScope() {
443 DCHECK(worker_task_runner_->RunsTasksOnCurrentThread());
444 DCHECK(provider_context_);
445 DCHECK(script_context_);
447 ServiceWorkerRegistrationObjectInfo info;
448 ServiceWorkerVersionAttributes attrs;
449 bool found =
450 provider_context_->GetRegistrationInfoAndVersionAttributes(&info, &attrs);
451 if (!found)
452 return; // Cannot be associated with a registration in some tests.
454 ServiceWorkerDispatcher* dispatcher =
455 ServiceWorkerDispatcher::GetOrCreateThreadSpecificInstance(
456 thread_safe_sender());
458 // Register a registration and its version attributes with the dispatcher
459 // living on the worker thread.
460 scoped_ptr<WebServiceWorkerRegistrationImpl> registration(
461 dispatcher->CreateServiceWorkerRegistration(info, false));
462 registration->SetInstalling(
463 dispatcher->GetServiceWorker(attrs.installing, false));
464 registration->SetWaiting(
465 dispatcher->GetServiceWorker(attrs.waiting, false));
466 registration->SetActive(
467 dispatcher->GetServiceWorker(attrs.active, false));
469 script_context_->SetRegistrationInServiceWorkerGlobalScope(
470 registration.Pass());
473 } // namespace content