Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / content / browser / service_worker / service_worker_internals_ui.cc
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.
4
5 #include "content/browser/service_worker/service_worker_internals_ui.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/bind.h"
11 #include "base/memory/scoped_vector.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/values.h"
14 #include "content/browser/devtools/devtools_manager_impl.h"
15 #include "content/browser/devtools/embedded_worker_devtools_manager.h"
16 #include "content/browser/service_worker/service_worker_context_observer.h"
17 #include "content/browser/service_worker/service_worker_context_wrapper.h"
18 #include "content/browser/service_worker/service_worker_registration.h"
19 #include "content/browser/service_worker/service_worker_version.h"
20 #include "content/public/browser/browser_context.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/browser/storage_partition.h"
23 #include "content/public/browser/web_contents.h"
24 #include "content/public/browser/web_ui.h"
25 #include "content/public/browser/web_ui_data_source.h"
26 #include "content/public/common/url_constants.h"
27 #include "grit/content_resources.h"
28
29 using base::DictionaryValue;
30 using base::FundamentalValue;
31 using base::ListValue;
32 using base::StringValue;
33 using base::Value;
34 using base::WeakPtr;
35
36 namespace content {
37
38 namespace {
39
40 void OperationCompleteCallback(WeakPtr<ServiceWorkerInternalsUI> internals,
41                                int callback_id,
42                                ServiceWorkerStatusCode status) {
43   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
44     BrowserThread::PostTask(
45         BrowserThread::UI,
46         FROM_HERE,
47         base::Bind(OperationCompleteCallback, internals, callback_id, status));
48     return;
49   }
50   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
51   if (internals) {
52     internals->web_ui()->CallJavascriptFunction(
53         "serviceworker.onOperationComplete",
54         FundamentalValue(static_cast<int>(status)),
55         FundamentalValue(callback_id));
56   }
57 }
58
59 void CallServiceWorkerVersionMethodWithVersionID(
60     ServiceWorkerInternalsUI::ServiceWorkerVersionMethod method,
61     scoped_refptr<ServiceWorkerContextWrapper> context,
62     int64 version_id,
63     const ServiceWorkerInternalsUI::StatusCallback& callback) {
64   if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
65     BrowserThread::PostTask(
66         BrowserThread::IO,
67         FROM_HERE,
68         base::Bind(CallServiceWorkerVersionMethodWithVersionID,
69                    method,
70                    context,
71                    version_id,
72                    callback));
73     return;
74   }
75   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
76   scoped_refptr<ServiceWorkerVersion> version =
77       context->context()->GetLiveVersion(version_id);
78   if (!version) {
79     callback.Run(SERVICE_WORKER_ERROR_NOT_FOUND);
80     return;
81   }
82   (*version.*method)(callback);
83 }
84
85 void DispatchPushEventWithVersionID(
86     scoped_refptr<ServiceWorkerContextWrapper> context,
87     int64 version_id,
88     const ServiceWorkerInternalsUI::StatusCallback& callback) {
89   if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
90     BrowserThread::PostTask(
91         BrowserThread::IO,
92         FROM_HERE,
93         base::Bind(DispatchPushEventWithVersionID,
94                    context,
95                    version_id,
96                    callback));
97     return;
98   }
99   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
100   scoped_refptr<ServiceWorkerVersion> version =
101       context->context()->GetLiveVersion(version_id);
102   if (!version) {
103     callback.Run(SERVICE_WORKER_ERROR_NOT_FOUND);
104     return;
105   }
106   std::string data = "Test push message from ServiceWorkerInternals.";
107   version->DispatchPushEvent(callback, data);
108 }
109
110 void UnregisterWithScope(
111     scoped_refptr<ServiceWorkerContextWrapper> context,
112     const GURL& scope,
113     const ServiceWorkerInternalsUI::StatusCallback& callback) {
114   if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
115     BrowserThread::PostTask(
116         BrowserThread::IO,
117         FROM_HERE,
118         base::Bind(UnregisterWithScope, context, scope, callback));
119     return;
120   }
121   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
122   context->context()->UnregisterServiceWorker(scope, callback);
123 }
124
125 void WorkerStarted(const scoped_refptr<ServiceWorkerRegistration>& registration,
126                    const ServiceWorkerInternalsUI::StatusCallback& callback,
127                    ServiceWorkerStatusCode status) {
128   callback.Run(status);
129 }
130
131 void StartActiveWorker(
132     const ServiceWorkerInternalsUI::StatusCallback& callback,
133     ServiceWorkerStatusCode status,
134     const scoped_refptr<ServiceWorkerRegistration>& registration) {
135   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
136   if (status == SERVICE_WORKER_OK) {
137     // Pass the reference of |registration| to WorkerStarted callback to prevent
138     // it from being deleted while starting the worker. If the refcount of
139     // |registration| is 1, it will be deleted after WorkerStarted is called.
140     registration->active_version()->StartWorker(
141         base::Bind(WorkerStarted, registration, callback));
142     return;
143   }
144   callback.Run(SERVICE_WORKER_ERROR_NOT_FOUND);
145 }
146
147 void FindRegistrationForPattern(
148     scoped_refptr<ServiceWorkerContextWrapper> context,
149     const GURL& scope,
150     const ServiceWorkerStorage::FindRegistrationCallback callback) {
151   if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
152     BrowserThread::PostTask(
153         BrowserThread::IO,
154         FROM_HERE,
155         base::Bind(FindRegistrationForPattern, context, scope, callback));
156     return;
157   }
158   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
159   context->context()->storage()->FindRegistrationForPattern(scope, callback);
160 }
161
162 void UpdateVersionInfo(const ServiceWorkerVersionInfo& version,
163                        DictionaryValue* info) {
164   switch (version.running_status) {
165     case ServiceWorkerVersion::STOPPED:
166       info->SetString("running_status", "STOPPED");
167       break;
168     case ServiceWorkerVersion::STARTING:
169       info->SetString("running_status", "STARTING");
170       break;
171     case ServiceWorkerVersion::RUNNING:
172       info->SetString("running_status", "RUNNING");
173       break;
174     case ServiceWorkerVersion::STOPPING:
175       info->SetString("running_status", "STOPPING");
176       break;
177   }
178
179   switch (version.status) {
180     case ServiceWorkerVersion::NEW:
181       info->SetString("status", "NEW");
182       break;
183     case ServiceWorkerVersion::INSTALLING:
184       info->SetString("status", "INSTALLING");
185       break;
186     case ServiceWorkerVersion::INSTALLED:
187       info->SetString("status", "INSTALLED");
188       break;
189     case ServiceWorkerVersion::ACTIVATING:
190       info->SetString("status", "ACTIVATING");
191       break;
192     case ServiceWorkerVersion::ACTIVATED:
193       info->SetString("status", "ACTIVATED");
194       break;
195     case ServiceWorkerVersion::REDUNDANT:
196       info->SetString("status", "REDUNDANT");
197       break;
198   }
199   info->SetString("version_id", base::Int64ToString(version.version_id));
200   info->SetInteger("process_id", version.process_id);
201   info->SetInteger("thread_id", version.thread_id);
202   info->SetInteger("devtools_agent_route_id", version.devtools_agent_route_id);
203 }
204
205 ListValue* GetRegistrationListValue(
206     const std::vector<ServiceWorkerRegistrationInfo>& registrations) {
207   ListValue* result = new ListValue();
208   for (std::vector<ServiceWorkerRegistrationInfo>::const_iterator it =
209            registrations.begin();
210        it != registrations.end();
211        ++it) {
212     const ServiceWorkerRegistrationInfo& registration = *it;
213     DictionaryValue* registration_info = new DictionaryValue();
214     registration_info->SetString("scope", registration.pattern.spec());
215     registration_info->SetString("script_url", registration.script_url.spec());
216     registration_info->SetString(
217         "registration_id", base::Int64ToString(registration.registration_id));
218
219     if (!registration.active_version.is_null) {
220       DictionaryValue* active_info = new DictionaryValue();
221       UpdateVersionInfo(registration.active_version, active_info);
222       registration_info->Set("active", active_info);
223     }
224
225     if (!registration.waiting_version.is_null) {
226       DictionaryValue* waiting_info = new DictionaryValue();
227       UpdateVersionInfo(registration.waiting_version, waiting_info);
228       registration_info->Set("waiting", waiting_info);
229     }
230
231     result->Append(registration_info);
232   }
233   return result;
234 }
235
236 ListValue* GetVersionListValue(
237     const std::vector<ServiceWorkerVersionInfo>& versions) {
238   ListValue* result = new ListValue();
239   for (std::vector<ServiceWorkerVersionInfo>::const_iterator it =
240            versions.begin();
241        it != versions.end();
242        ++it) {
243     DictionaryValue* info = new DictionaryValue();
244     UpdateVersionInfo(*it, info);
245     result->Append(info);
246   }
247   return result;
248 }
249
250 void GetRegistrationsOnIOThread(
251     scoped_refptr<ServiceWorkerContextWrapper> context,
252     base::Callback<void(const std::vector<ServiceWorkerRegistrationInfo>&)>
253         callback) {
254   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
255   context->context()->storage()->GetAllRegistrations(callback);
256 }
257
258 void OnStoredRegistrations(
259     scoped_refptr<ServiceWorkerContextWrapper> context,
260     base::Callback<void(const std::vector<ServiceWorkerRegistrationInfo>&,
261                         const std::vector<ServiceWorkerVersionInfo>&,
262                         const std::vector<ServiceWorkerRegistrationInfo>&)>
263         callback,
264     const std::vector<ServiceWorkerRegistrationInfo>& stored_registrations) {
265   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
266   BrowserThread::PostTask(
267       BrowserThread::UI,
268       FROM_HERE,
269       base::Bind(callback,
270                  context->context()->GetAllLiveRegistrationInfo(),
271                  context->context()->GetAllLiveVersionInfo(),
272                  stored_registrations));
273 }
274
275 void OnAllRegistrations(
276     WeakPtr<ServiceWorkerInternalsUI> internals,
277     int partition_id,
278     const base::FilePath& context_path,
279     const std::vector<ServiceWorkerRegistrationInfo>& live_registrations,
280     const std::vector<ServiceWorkerVersionInfo>& live_versions,
281     const std::vector<ServiceWorkerRegistrationInfo>& stored_registrations) {
282   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
283   if (!internals)
284     return;
285
286   ScopedVector<const Value> args;
287   args.push_back(GetRegistrationListValue(live_registrations));
288   args.push_back(GetVersionListValue(live_versions));
289   args.push_back(GetRegistrationListValue(stored_registrations));
290   args.push_back(new FundamentalValue(partition_id));
291   args.push_back(new StringValue(context_path.value()));
292   internals->web_ui()->CallJavascriptFunction("serviceworker.onPartitionData",
293                                               args.get());
294 }
295
296 }  // namespace
297
298 class ServiceWorkerInternalsUI::PartitionObserver
299     : public ServiceWorkerContextObserver {
300  public:
301   PartitionObserver(int partition_id, WebUI* web_ui)
302       : partition_id_(partition_id), web_ui_(web_ui) {}
303   virtual ~PartitionObserver() {}
304   // ServiceWorkerContextObserver overrides:
305   virtual void OnWorkerStarted(int64 version_id,
306                                int process_id,
307                                int thread_id) OVERRIDE {
308     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
309     web_ui_->CallJavascriptFunction(
310         "serviceworker.onWorkerStarted",
311         FundamentalValue(partition_id_),
312         StringValue(base::Int64ToString(version_id)),
313         FundamentalValue(process_id),
314         FundamentalValue(thread_id));
315   }
316   virtual void OnWorkerStopped(int64 version_id,
317                                int process_id,
318                                int thread_id) OVERRIDE {
319     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
320     web_ui_->CallJavascriptFunction(
321         "serviceworker.onWorkerStopped",
322         FundamentalValue(partition_id_),
323         StringValue(base::Int64ToString(version_id)),
324         FundamentalValue(process_id),
325         FundamentalValue(thread_id));
326   }
327   virtual void OnVersionStateChanged(int64 version_id) OVERRIDE {
328     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
329     web_ui_->CallJavascriptFunction(
330         "serviceworker.onVersionStateChanged",
331         FundamentalValue(partition_id_),
332         StringValue(base::Int64ToString(version_id)));
333   }
334   virtual void OnErrorReported(int64 version_id,
335                                int process_id,
336                                int thread_id,
337                                const ErrorInfo& info) OVERRIDE {
338     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
339     ScopedVector<const Value> args;
340     args.push_back(new FundamentalValue(partition_id_));
341     args.push_back(new StringValue(base::Int64ToString(version_id)));
342     args.push_back(new FundamentalValue(process_id));
343     args.push_back(new FundamentalValue(thread_id));
344     scoped_ptr<DictionaryValue> value(new DictionaryValue());
345     value->SetString("message", info.error_message);
346     value->SetInteger("lineNumber", info.line_number);
347     value->SetInteger("columnNumber", info.column_number);
348     value->SetString("sourceURL", info.source_url.spec());
349     args.push_back(value.release());
350     web_ui_->CallJavascriptFunction("serviceworker.onErrorReported",
351                                     args.get());
352   }
353   virtual void OnReportConsoleMessage(int64 version_id,
354                                       int process_id,
355                                       int thread_id,
356                                       const ConsoleMessage& message) OVERRIDE {
357     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
358     ScopedVector<const Value> args;
359     args.push_back(new FundamentalValue(partition_id_));
360     args.push_back(new StringValue(base::Int64ToString(version_id)));
361     args.push_back(new FundamentalValue(process_id));
362     args.push_back(new FundamentalValue(thread_id));
363     scoped_ptr<DictionaryValue> value(new DictionaryValue());
364     value->SetInteger("sourceIdentifier", message.source_identifier);
365     value->SetInteger("message_level", message.message_level);
366     value->SetString("message", message.message);
367     value->SetInteger("lineNumber", message.line_number);
368     value->SetString("sourceURL", message.source_url.spec());
369     args.push_back(value.release());
370     web_ui_->CallJavascriptFunction("serviceworker.onConsoleMessageReported",
371                                     args.get());
372   }
373   virtual void OnRegistrationStored(const GURL& pattern) OVERRIDE {
374     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
375     web_ui_->CallJavascriptFunction("serviceworker.onRegistrationStored",
376                                     StringValue(pattern.spec()));
377   }
378   virtual void OnRegistrationDeleted(const GURL& pattern) OVERRIDE {
379     web_ui_->CallJavascriptFunction("serviceworker.onRegistrationDeleted",
380                                     StringValue(pattern.spec()));
381   }
382   int partition_id() const { return partition_id_; }
383
384  private:
385   const int partition_id_;
386   WebUI* const web_ui_;
387 };
388
389 ServiceWorkerInternalsUI::ServiceWorkerInternalsUI(WebUI* web_ui)
390     : WebUIController(web_ui), next_partition_id_(0) {
391   WebUIDataSource* source =
392       WebUIDataSource::Create(kChromeUIServiceWorkerInternalsHost);
393   source->SetUseJsonJSFormatV2();
394   source->SetJsonPath("strings.js");
395   source->AddResourcePath("serviceworker_internals.js",
396                           IDR_SERVICE_WORKER_INTERNALS_JS);
397   source->AddResourcePath("serviceworker_internals.css",
398                           IDR_SERVICE_WORKER_INTERNALS_CSS);
399   source->SetDefaultResource(IDR_SERVICE_WORKER_INTERNALS_HTML);
400   source->DisableDenyXFrameOptions();
401
402   BrowserContext* browser_context =
403       web_ui->GetWebContents()->GetBrowserContext();
404   WebUIDataSource::Add(browser_context, source);
405
406   web_ui->RegisterMessageCallback(
407       "GetOptions",
408       base::Bind(&ServiceWorkerInternalsUI::GetOptions,
409                  base::Unretained(this)));
410   web_ui->RegisterMessageCallback(
411       "SetOption",
412       base::Bind(&ServiceWorkerInternalsUI::SetOption, base::Unretained(this)));
413   web_ui->RegisterMessageCallback(
414       "getAllRegistrations",
415       base::Bind(&ServiceWorkerInternalsUI::GetAllRegistrations,
416                  base::Unretained(this)));
417   web_ui->RegisterMessageCallback(
418       "stop",
419       base::Bind(&ServiceWorkerInternalsUI::CallServiceWorkerVersionMethod,
420                  base::Unretained(this),
421                  &ServiceWorkerVersion::StopWorker));
422   web_ui->RegisterMessageCallback(
423       "sync",
424       base::Bind(&ServiceWorkerInternalsUI::CallServiceWorkerVersionMethod,
425                  base::Unretained(this),
426                  &ServiceWorkerVersion::DispatchSyncEvent));
427   web_ui->RegisterMessageCallback(
428       "push",
429       base::Bind(&ServiceWorkerInternalsUI::DispatchPushEvent,
430                  base::Unretained(this)));
431   web_ui->RegisterMessageCallback(
432       "inspect",
433       base::Bind(&ServiceWorkerInternalsUI::InspectWorker,
434                  base::Unretained(this)));
435   web_ui->RegisterMessageCallback(
436       "unregister",
437       base::Bind(&ServiceWorkerInternalsUI::Unregister,
438                  base::Unretained(this)));
439   web_ui->RegisterMessageCallback(
440       "start",
441       base::Bind(&ServiceWorkerInternalsUI::StartWorker,
442                  base::Unretained(this)));
443 }
444
445 ServiceWorkerInternalsUI::~ServiceWorkerInternalsUI() {
446   BrowserContext* browser_context =
447       web_ui()->GetWebContents()->GetBrowserContext();
448   // Safe to use base::Unretained(this) because
449   // ForEachStoragePartition is synchronous.
450   BrowserContext::StoragePartitionCallback remove_observer_cb =
451       base::Bind(&ServiceWorkerInternalsUI::RemoveObserverFromStoragePartition,
452                  base::Unretained(this));
453   BrowserContext::ForEachStoragePartition(browser_context, remove_observer_cb);
454 }
455
456 void ServiceWorkerInternalsUI::GetOptions(const ListValue* args) {
457   DictionaryValue options;
458   options.SetBoolean("debug_on_start",
459                      EmbeddedWorkerDevToolsManager::GetInstance()
460                          ->debug_service_worker_on_start());
461   web_ui()->CallJavascriptFunction("serviceworker.onOptions", options);
462 }
463
464 void ServiceWorkerInternalsUI::SetOption(const ListValue* args) {
465   std::string option_name;
466   bool option_boolean;
467   if (!args->GetString(0, &option_name) || option_name != "debug_on_start" ||
468       !args->GetBoolean(1, &option_boolean)) {
469     return;
470   }
471   EmbeddedWorkerDevToolsManager::GetInstance()
472       ->set_debug_service_worker_on_start(option_boolean);
473 }
474
475 void ServiceWorkerInternalsUI::GetAllRegistrations(const ListValue* args) {
476   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
477   BrowserContext* browser_context =
478       web_ui()->GetWebContents()->GetBrowserContext();
479   // Safe to use base::Unretained(this) because
480   // ForEachStoragePartition is synchronous.
481   BrowserContext::StoragePartitionCallback add_context_cb =
482       base::Bind(&ServiceWorkerInternalsUI::AddContextFromStoragePartition,
483                  base::Unretained(this));
484   BrowserContext::ForEachStoragePartition(browser_context, add_context_cb);
485 }
486
487 void ServiceWorkerInternalsUI::AddContextFromStoragePartition(
488     StoragePartition* partition) {
489   int partition_id = 0;
490   scoped_refptr<ServiceWorkerContextWrapper> context =
491       static_cast<ServiceWorkerContextWrapper*>(
492           partition->GetServiceWorkerContext());
493   if (PartitionObserver* observer =
494           observers_.get(reinterpret_cast<uintptr_t>(partition))) {
495     partition_id = observer->partition_id();
496   } else {
497     partition_id = next_partition_id_++;
498     scoped_ptr<PartitionObserver> new_observer(
499         new PartitionObserver(partition_id, web_ui()));
500     context->AddObserver(new_observer.get());
501     observers_.set(reinterpret_cast<uintptr_t>(partition), new_observer.Pass());
502   }
503
504   BrowserThread::PostTask(
505       BrowserThread::IO,
506       FROM_HERE,
507       base::Bind(GetRegistrationsOnIOThread,
508                  context,
509                  base::Bind(OnStoredRegistrations,
510                             context,
511                             base::Bind(OnAllRegistrations,
512                                        AsWeakPtr(),
513                                        partition_id,
514                                        context->is_incognito()
515                                            ? base::FilePath()
516                                            : partition->GetPath()))));
517 }
518
519 void ServiceWorkerInternalsUI::RemoveObserverFromStoragePartition(
520     StoragePartition* partition) {
521   scoped_ptr<PartitionObserver> observer(
522       observers_.take_and_erase(reinterpret_cast<uintptr_t>(partition)));
523   if (!observer.get())
524     return;
525   scoped_refptr<ServiceWorkerContextWrapper> context =
526       static_cast<ServiceWorkerContextWrapper*>(
527           partition->GetServiceWorkerContext());
528   context->RemoveObserver(observer.get());
529 }
530
531 void ServiceWorkerInternalsUI::FindContext(
532     int partition_id,
533     StoragePartition** result_partition,
534     StoragePartition* storage_partition) const {
535   PartitionObserver* observer =
536       observers_.get(reinterpret_cast<uintptr_t>(storage_partition));
537   if (observer && partition_id == observer->partition_id()) {
538     *result_partition = storage_partition;
539   }
540 }
541
542 bool ServiceWorkerInternalsUI::GetServiceWorkerContext(
543     int partition_id,
544     scoped_refptr<ServiceWorkerContextWrapper>* context) const {
545   BrowserContext* browser_context =
546       web_ui()->GetWebContents()->GetBrowserContext();
547   StoragePartition* result_partition(NULL);
548   BrowserContext::StoragePartitionCallback find_context_cb =
549       base::Bind(&ServiceWorkerInternalsUI::FindContext,
550                  base::Unretained(this),
551                  partition_id,
552                  &result_partition);
553   BrowserContext::ForEachStoragePartition(browser_context, find_context_cb);
554   if (!result_partition)
555     return false;
556   *context = static_cast<ServiceWorkerContextWrapper*>(
557       result_partition->GetServiceWorkerContext());
558   return true;
559 }
560
561 void ServiceWorkerInternalsUI::CallServiceWorkerVersionMethod(
562     ServiceWorkerVersionMethod method,
563     const ListValue* args) {
564   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
565   int callback_id;
566   const DictionaryValue* cmd_args = NULL;
567   int partition_id;
568   scoped_refptr<ServiceWorkerContextWrapper> context;
569   std::string version_id_string;
570   int64 version_id = 0;
571   if (!args->GetInteger(0, &callback_id) ||
572       !args->GetDictionary(1, &cmd_args) ||
573       !cmd_args->GetInteger("partition_id", &partition_id) ||
574       !GetServiceWorkerContext(partition_id, &context) ||
575       !cmd_args->GetString("version_id", &version_id_string) ||
576       !base::StringToInt64(version_id_string, &version_id)) {
577     return;
578   }
579
580   base::Callback<void(ServiceWorkerStatusCode)> callback =
581       base::Bind(OperationCompleteCallback, AsWeakPtr(), callback_id);
582   CallServiceWorkerVersionMethodWithVersionID(
583       method, context, version_id, callback);
584 }
585
586 void ServiceWorkerInternalsUI::DispatchPushEvent(
587     const ListValue* args) {
588   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
589   int callback_id;
590   int partition_id;
591   int64 version_id = 0;
592   std::string version_id_string;
593   const DictionaryValue* cmd_args = NULL;
594   scoped_refptr<ServiceWorkerContextWrapper> context;
595   if (!args->GetInteger(0, &callback_id) ||
596       !args->GetDictionary(1, &cmd_args) ||
597       !cmd_args->GetInteger("partition_id", &partition_id) ||
598       !GetServiceWorkerContext(partition_id, &context) ||
599       !cmd_args->GetString("version_id", &version_id_string) ||
600       !base::StringToInt64(version_id_string, &version_id)) {
601     return;
602   }
603
604   base::Callback<void(ServiceWorkerStatusCode)> callback =
605       base::Bind(OperationCompleteCallback, AsWeakPtr(), callback_id);
606   DispatchPushEventWithVersionID(context, version_id, callback);
607 }
608
609 void ServiceWorkerInternalsUI::InspectWorker(const ListValue* args) {
610   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
611   int callback_id;
612   const DictionaryValue* cmd_args = NULL;
613   int process_id = 0;
614   int devtools_agent_route_id = 0;
615   if (!args->GetInteger(0, &callback_id) ||
616       !args->GetDictionary(1, &cmd_args) ||
617       !cmd_args->GetInteger("process_id", &process_id) ||
618       !cmd_args->GetInteger("devtools_agent_route_id",
619                             &devtools_agent_route_id)) {
620     return;
621   }
622   base::Callback<void(ServiceWorkerStatusCode)> callback =
623       base::Bind(OperationCompleteCallback, AsWeakPtr(), callback_id);
624   scoped_refptr<DevToolsAgentHost> agent_host(
625       EmbeddedWorkerDevToolsManager::GetInstance()
626           ->GetDevToolsAgentHostForWorker(process_id, devtools_agent_route_id));
627   if (!agent_host) {
628     callback.Run(SERVICE_WORKER_ERROR_NOT_FOUND);
629     return;
630   }
631   DevToolsManagerImpl::GetInstance()->Inspect(
632       web_ui()->GetWebContents()->GetBrowserContext(), agent_host.get());
633   callback.Run(SERVICE_WORKER_OK);
634 }
635
636 void ServiceWorkerInternalsUI::Unregister(const ListValue* args) {
637   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
638   int callback_id;
639   int partition_id;
640   std::string scope_string;
641   const DictionaryValue* cmd_args = NULL;
642   scoped_refptr<ServiceWorkerContextWrapper> context;
643   if (!args->GetInteger(0, &callback_id) ||
644       !args->GetDictionary(1, &cmd_args) ||
645       !cmd_args->GetInteger("partition_id", &partition_id) ||
646       !GetServiceWorkerContext(partition_id, &context) ||
647       !cmd_args->GetString("scope", &scope_string)) {
648     return;
649   }
650
651   base::Callback<void(ServiceWorkerStatusCode)> callback =
652       base::Bind(OperationCompleteCallback, AsWeakPtr(), callback_id);
653   UnregisterWithScope(context, GURL(scope_string), callback);
654 }
655
656 void ServiceWorkerInternalsUI::StartWorker(const ListValue* args) {
657   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
658   int callback_id;
659   int partition_id;
660   std::string scope_string;
661   const DictionaryValue* cmd_args = NULL;
662   scoped_refptr<ServiceWorkerContextWrapper> context;
663   if (!args->GetInteger(0, &callback_id) ||
664       !args->GetDictionary(1, &cmd_args) ||
665       !cmd_args->GetInteger("partition_id", &partition_id) ||
666       !GetServiceWorkerContext(partition_id, &context) ||
667       !cmd_args->GetString("scope", &scope_string)) {
668     return;
669   }
670
671   base::Callback<void(ServiceWorkerStatusCode)> callback =
672       base::Bind(OperationCompleteCallback, AsWeakPtr(), callback_id);
673   FindRegistrationForPattern(
674       context, GURL(scope_string), base::Bind(StartActiveWorker, callback));
675 }
676
677 }  // namespace content