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