Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_internals_ui.cc
blob0e50fa4b89453002c503b61f1b7432dbce2b0bed
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/browser/service_worker/service_worker_internals_ui.h"
7 #include <string>
8 #include <vector>
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_agent_host_impl.h"
15 #include "content/browser/devtools/service_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/grit/content_resources.h"
21 #include "content/public/browser/browser_context.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/storage_partition.h"
24 #include "content/public/browser/web_contents.h"
25 #include "content/public/browser/web_ui.h"
26 #include "content/public/browser/web_ui_data_source.h"
27 #include "content/public/common/url_constants.h"
29 using base::DictionaryValue;
30 using base::FundamentalValue;
31 using base::ListValue;
32 using base::StringValue;
33 using base::Value;
34 using base::WeakPtr;
36 namespace content {
38 namespace {
40 using GetRegistrationsCallback =
41 base::Callback<void(const std::vector<ServiceWorkerRegistrationInfo>&,
42 const std::vector<ServiceWorkerVersionInfo>&,
43 const std::vector<ServiceWorkerRegistrationInfo>&)>;
45 void OperationCompleteCallback(WeakPtr<ServiceWorkerInternalsUI> internals,
46 int callback_id,
47 ServiceWorkerStatusCode status) {
48 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
49 BrowserThread::PostTask(
50 BrowserThread::UI,
51 FROM_HERE,
52 base::Bind(OperationCompleteCallback, internals, callback_id, status));
53 return;
55 DCHECK_CURRENTLY_ON(BrowserThread::UI);
56 if (internals) {
57 internals->web_ui()->CallJavascriptFunction(
58 "serviceworker.onOperationComplete",
59 FundamentalValue(static_cast<int>(status)),
60 FundamentalValue(callback_id));
64 void CallServiceWorkerVersionMethodWithVersionID(
65 ServiceWorkerInternalsUI::ServiceWorkerVersionMethod method,
66 scoped_refptr<ServiceWorkerContextWrapper> context,
67 int64 version_id,
68 const ServiceWorkerInternalsUI::StatusCallback& callback) {
69 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
70 BrowserThread::PostTask(
71 BrowserThread::IO,
72 FROM_HERE,
73 base::Bind(CallServiceWorkerVersionMethodWithVersionID,
74 method,
75 context,
76 version_id,
77 callback));
78 return;
81 scoped_refptr<ServiceWorkerVersion> version =
82 context->GetLiveVersion(version_id);
83 if (!version.get()) {
84 callback.Run(SERVICE_WORKER_ERROR_NOT_FOUND);
85 return;
87 (*version.get().*method)(callback);
90 void DispatchPushEventWithVersionID(
91 scoped_refptr<ServiceWorkerContextWrapper> context,
92 int64 version_id,
93 const ServiceWorkerInternalsUI::StatusCallback& callback) {
94 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
95 BrowserThread::PostTask(
96 BrowserThread::IO,
97 FROM_HERE,
98 base::Bind(DispatchPushEventWithVersionID,
99 context,
100 version_id,
101 callback));
102 return;
105 scoped_refptr<ServiceWorkerVersion> version =
106 context->GetLiveVersion(version_id);
107 if (!version.get()) {
108 callback.Run(SERVICE_WORKER_ERROR_NOT_FOUND);
109 return;
111 std::string data = "Test push message from ServiceWorkerInternals.";
112 version->DispatchPushEvent(callback, data);
115 void UpdateVersionInfo(const ServiceWorkerVersionInfo& version,
116 DictionaryValue* info) {
117 switch (version.running_status) {
118 case ServiceWorkerVersion::STOPPED:
119 info->SetString("running_status", "STOPPED");
120 break;
121 case ServiceWorkerVersion::STARTING:
122 info->SetString("running_status", "STARTING");
123 break;
124 case ServiceWorkerVersion::RUNNING:
125 info->SetString("running_status", "RUNNING");
126 break;
127 case ServiceWorkerVersion::STOPPING:
128 info->SetString("running_status", "STOPPING");
129 break;
132 switch (version.status) {
133 case ServiceWorkerVersion::NEW:
134 info->SetString("status", "NEW");
135 break;
136 case ServiceWorkerVersion::INSTALLING:
137 info->SetString("status", "INSTALLING");
138 break;
139 case ServiceWorkerVersion::INSTALLED:
140 info->SetString("status", "INSTALLED");
141 break;
142 case ServiceWorkerVersion::ACTIVATING:
143 info->SetString("status", "ACTIVATING");
144 break;
145 case ServiceWorkerVersion::ACTIVATED:
146 info->SetString("status", "ACTIVATED");
147 break;
148 case ServiceWorkerVersion::REDUNDANT:
149 info->SetString("status", "REDUNDANT");
150 break;
152 info->SetString("script_url", version.script_url.spec());
153 info->SetString("version_id", base::Int64ToString(version.version_id));
154 info->SetInteger("process_id", version.process_id);
155 info->SetInteger("thread_id", version.thread_id);
156 info->SetInteger("devtools_agent_route_id", version.devtools_agent_route_id);
159 ListValue* GetRegistrationListValue(
160 const std::vector<ServiceWorkerRegistrationInfo>& registrations) {
161 ListValue* result = new ListValue();
162 for (std::vector<ServiceWorkerRegistrationInfo>::const_iterator it =
163 registrations.begin();
164 it != registrations.end();
165 ++it) {
166 const ServiceWorkerRegistrationInfo& registration = *it;
167 DictionaryValue* registration_info = new DictionaryValue();
168 registration_info->SetString("scope", registration.pattern.spec());
169 registration_info->SetString(
170 "registration_id", base::Int64ToString(registration.registration_id));
172 if (registration.active_version.version_id !=
173 kInvalidServiceWorkerVersionId) {
174 DictionaryValue* active_info = new DictionaryValue();
175 UpdateVersionInfo(registration.active_version, active_info);
176 registration_info->Set("active", active_info);
179 if (registration.waiting_version.version_id !=
180 kInvalidServiceWorkerVersionId) {
181 DictionaryValue* waiting_info = new DictionaryValue();
182 UpdateVersionInfo(registration.waiting_version, waiting_info);
183 registration_info->Set("waiting", waiting_info);
186 result->Append(registration_info);
188 return result;
191 ListValue* GetVersionListValue(
192 const std::vector<ServiceWorkerVersionInfo>& versions) {
193 ListValue* result = new ListValue();
194 for (std::vector<ServiceWorkerVersionInfo>::const_iterator it =
195 versions.begin();
196 it != versions.end();
197 ++it) {
198 DictionaryValue* info = new DictionaryValue();
199 UpdateVersionInfo(*it, info);
200 result->Append(info);
202 return result;
205 void DidGetStoredRegistrationsOnIOThread(
206 scoped_refptr<ServiceWorkerContextWrapper> context,
207 const GetRegistrationsCallback& callback,
208 const std::vector<ServiceWorkerRegistrationInfo>& stored_registrations) {
209 DCHECK_CURRENTLY_ON(BrowserThread::IO);
210 BrowserThread::PostTask(
211 BrowserThread::UI, FROM_HERE,
212 base::Bind(callback, context->GetAllLiveRegistrationInfo(),
213 context->GetAllLiveVersionInfo(), stored_registrations));
216 void GetRegistrationsOnIOThread(
217 scoped_refptr<ServiceWorkerContextWrapper> context,
218 const GetRegistrationsCallback& callback) {
219 DCHECK_CURRENTLY_ON(BrowserThread::IO);
220 context->GetAllRegistrations(
221 base::Bind(DidGetStoredRegistrationsOnIOThread, context, callback));
224 void DidGetRegistrations(
225 WeakPtr<ServiceWorkerInternalsUI> internals,
226 int partition_id,
227 const base::FilePath& context_path,
228 const std::vector<ServiceWorkerRegistrationInfo>& live_registrations,
229 const std::vector<ServiceWorkerVersionInfo>& live_versions,
230 const std::vector<ServiceWorkerRegistrationInfo>& stored_registrations) {
231 DCHECK_CURRENTLY_ON(BrowserThread::UI);
232 if (!internals)
233 return;
235 ScopedVector<const Value> args;
236 args.push_back(GetRegistrationListValue(live_registrations));
237 args.push_back(GetVersionListValue(live_versions));
238 args.push_back(GetRegistrationListValue(stored_registrations));
239 args.push_back(new FundamentalValue(partition_id));
240 args.push_back(new StringValue(context_path.value()));
241 internals->web_ui()->CallJavascriptFunction("serviceworker.onPartitionData",
242 args.get());
245 } // namespace
247 class ServiceWorkerInternalsUI::PartitionObserver
248 : public ServiceWorkerContextObserver {
249 public:
250 PartitionObserver(int partition_id, WebUI* web_ui)
251 : partition_id_(partition_id), web_ui_(web_ui) {}
252 ~PartitionObserver() override {}
253 // ServiceWorkerContextObserver overrides:
254 void OnRunningStateChanged(int64 version_id,
255 ServiceWorkerVersion::RunningStatus) override {
256 DCHECK_CURRENTLY_ON(BrowserThread::UI);
257 web_ui_->CallJavascriptFunction(
258 "serviceworker.onRunningStateChanged", FundamentalValue(partition_id_),
259 StringValue(base::Int64ToString(version_id)));
261 void OnVersionStateChanged(int64 version_id,
262 ServiceWorkerVersion::Status) override {
263 DCHECK_CURRENTLY_ON(BrowserThread::UI);
264 web_ui_->CallJavascriptFunction(
265 "serviceworker.onVersionStateChanged",
266 FundamentalValue(partition_id_),
267 StringValue(base::Int64ToString(version_id)));
269 void OnErrorReported(int64 version_id,
270 int process_id,
271 int thread_id,
272 const ErrorInfo& info) override {
273 DCHECK_CURRENTLY_ON(BrowserThread::UI);
274 ScopedVector<const Value> args;
275 args.push_back(new FundamentalValue(partition_id_));
276 args.push_back(new StringValue(base::Int64ToString(version_id)));
277 args.push_back(new FundamentalValue(process_id));
278 args.push_back(new FundamentalValue(thread_id));
279 scoped_ptr<DictionaryValue> value(new DictionaryValue());
280 value->SetString("message", info.error_message);
281 value->SetInteger("lineNumber", info.line_number);
282 value->SetInteger("columnNumber", info.column_number);
283 value->SetString("sourceURL", info.source_url.spec());
284 args.push_back(value.release());
285 web_ui_->CallJavascriptFunction("serviceworker.onErrorReported",
286 args.get());
288 void OnReportConsoleMessage(int64 version_id,
289 int process_id,
290 int thread_id,
291 const ConsoleMessage& message) override {
292 DCHECK_CURRENTLY_ON(BrowserThread::UI);
293 ScopedVector<const Value> args;
294 args.push_back(new FundamentalValue(partition_id_));
295 args.push_back(new StringValue(base::Int64ToString(version_id)));
296 args.push_back(new FundamentalValue(process_id));
297 args.push_back(new FundamentalValue(thread_id));
298 scoped_ptr<DictionaryValue> value(new DictionaryValue());
299 value->SetInteger("sourceIdentifier", message.source_identifier);
300 value->SetInteger("message_level", message.message_level);
301 value->SetString("message", message.message);
302 value->SetInteger("lineNumber", message.line_number);
303 value->SetString("sourceURL", message.source_url.spec());
304 args.push_back(value.release());
305 web_ui_->CallJavascriptFunction("serviceworker.onConsoleMessageReported",
306 args.get());
308 void OnRegistrationStored(int64 registration_id,
309 const GURL& pattern) override {
310 DCHECK_CURRENTLY_ON(BrowserThread::UI);
311 web_ui_->CallJavascriptFunction("serviceworker.onRegistrationStored",
312 StringValue(pattern.spec()));
314 void OnRegistrationDeleted(int64 registration_id,
315 const GURL& pattern) override {
316 web_ui_->CallJavascriptFunction("serviceworker.onRegistrationDeleted",
317 StringValue(pattern.spec()));
319 int partition_id() const { return partition_id_; }
321 private:
322 const int partition_id_;
323 WebUI* const web_ui_;
326 ServiceWorkerInternalsUI::ServiceWorkerInternalsUI(WebUI* web_ui)
327 : WebUIController(web_ui), next_partition_id_(0) {
328 WebUIDataSource* source =
329 WebUIDataSource::Create(kChromeUIServiceWorkerInternalsHost);
330 source->SetJsonPath("strings.js");
331 source->AddResourcePath("serviceworker_internals.js",
332 IDR_SERVICE_WORKER_INTERNALS_JS);
333 source->AddResourcePath("serviceworker_internals.css",
334 IDR_SERVICE_WORKER_INTERNALS_CSS);
335 source->SetDefaultResource(IDR_SERVICE_WORKER_INTERNALS_HTML);
336 source->DisableDenyXFrameOptions();
338 BrowserContext* browser_context =
339 web_ui->GetWebContents()->GetBrowserContext();
340 WebUIDataSource::Add(browser_context, source);
342 web_ui->RegisterMessageCallback(
343 "GetOptions",
344 base::Bind(&ServiceWorkerInternalsUI::GetOptions,
345 base::Unretained(this)));
346 web_ui->RegisterMessageCallback(
347 "SetOption",
348 base::Bind(&ServiceWorkerInternalsUI::SetOption, base::Unretained(this)));
349 web_ui->RegisterMessageCallback(
350 "getAllRegistrations",
351 base::Bind(&ServiceWorkerInternalsUI::GetAllRegistrations,
352 base::Unretained(this)));
353 web_ui->RegisterMessageCallback(
354 "stop",
355 base::Bind(&ServiceWorkerInternalsUI::CallServiceWorkerVersionMethod,
356 base::Unretained(this),
357 &ServiceWorkerVersion::StopWorker));
358 web_ui->RegisterMessageCallback(
359 "push",
360 base::Bind(&ServiceWorkerInternalsUI::DispatchPushEvent,
361 base::Unretained(this)));
362 web_ui->RegisterMessageCallback(
363 "inspect",
364 base::Bind(&ServiceWorkerInternalsUI::InspectWorker,
365 base::Unretained(this)));
366 web_ui->RegisterMessageCallback(
367 "unregister",
368 base::Bind(&ServiceWorkerInternalsUI::Unregister,
369 base::Unretained(this)));
370 web_ui->RegisterMessageCallback(
371 "start",
372 base::Bind(&ServiceWorkerInternalsUI::StartWorker,
373 base::Unretained(this)));
376 ServiceWorkerInternalsUI::~ServiceWorkerInternalsUI() {
377 BrowserContext* browser_context =
378 web_ui()->GetWebContents()->GetBrowserContext();
379 // Safe to use base::Unretained(this) because
380 // ForEachStoragePartition is synchronous.
381 BrowserContext::StoragePartitionCallback remove_observer_cb =
382 base::Bind(&ServiceWorkerInternalsUI::RemoveObserverFromStoragePartition,
383 base::Unretained(this));
384 BrowserContext::ForEachStoragePartition(browser_context, remove_observer_cb);
387 void ServiceWorkerInternalsUI::GetOptions(const ListValue* args) {
388 DictionaryValue options;
389 options.SetBoolean("debug_on_start",
390 ServiceWorkerDevToolsManager::GetInstance()
391 ->debug_service_worker_on_start());
392 web_ui()->CallJavascriptFunction("serviceworker.onOptions", options);
395 void ServiceWorkerInternalsUI::SetOption(const ListValue* args) {
396 std::string option_name;
397 bool option_boolean;
398 if (!args->GetString(0, &option_name) || option_name != "debug_on_start" ||
399 !args->GetBoolean(1, &option_boolean)) {
400 return;
402 ServiceWorkerDevToolsManager::GetInstance()
403 ->set_debug_service_worker_on_start(option_boolean);
406 void ServiceWorkerInternalsUI::GetAllRegistrations(const ListValue* args) {
407 DCHECK_CURRENTLY_ON(BrowserThread::UI);
408 BrowserContext* browser_context =
409 web_ui()->GetWebContents()->GetBrowserContext();
410 // Safe to use base::Unretained(this) because
411 // ForEachStoragePartition is synchronous.
412 BrowserContext::StoragePartitionCallback add_context_cb =
413 base::Bind(&ServiceWorkerInternalsUI::AddContextFromStoragePartition,
414 base::Unretained(this));
415 BrowserContext::ForEachStoragePartition(browser_context, add_context_cb);
418 void ServiceWorkerInternalsUI::AddContextFromStoragePartition(
419 StoragePartition* partition) {
420 int partition_id = 0;
421 scoped_refptr<ServiceWorkerContextWrapper> context =
422 static_cast<ServiceWorkerContextWrapper*>(
423 partition->GetServiceWorkerContext());
424 if (PartitionObserver* observer =
425 observers_.get(reinterpret_cast<uintptr_t>(partition))) {
426 partition_id = observer->partition_id();
427 } else {
428 partition_id = next_partition_id_++;
429 scoped_ptr<PartitionObserver> new_observer(
430 new PartitionObserver(partition_id, web_ui()));
431 context->AddObserver(new_observer.get());
432 observers_.set(reinterpret_cast<uintptr_t>(partition), new_observer.Pass());
435 BrowserThread::PostTask(
436 BrowserThread::IO, FROM_HERE,
437 base::Bind(GetRegistrationsOnIOThread, context,
438 base::Bind(DidGetRegistrations, AsWeakPtr(), partition_id,
439 context->is_incognito() ? base::FilePath()
440 : partition->GetPath())));
443 void ServiceWorkerInternalsUI::RemoveObserverFromStoragePartition(
444 StoragePartition* partition) {
445 scoped_ptr<PartitionObserver> observer(
446 observers_.take_and_erase(reinterpret_cast<uintptr_t>(partition)));
447 if (!observer.get())
448 return;
449 scoped_refptr<ServiceWorkerContextWrapper> context =
450 static_cast<ServiceWorkerContextWrapper*>(
451 partition->GetServiceWorkerContext());
452 context->RemoveObserver(observer.get());
455 void ServiceWorkerInternalsUI::FindContext(
456 int partition_id,
457 StoragePartition** result_partition,
458 StoragePartition* storage_partition) const {
459 PartitionObserver* observer =
460 observers_.get(reinterpret_cast<uintptr_t>(storage_partition));
461 if (observer && partition_id == observer->partition_id()) {
462 *result_partition = storage_partition;
466 bool ServiceWorkerInternalsUI::GetServiceWorkerContext(
467 int partition_id,
468 scoped_refptr<ServiceWorkerContextWrapper>* context) const {
469 BrowserContext* browser_context =
470 web_ui()->GetWebContents()->GetBrowserContext();
471 StoragePartition* result_partition(NULL);
472 BrowserContext::StoragePartitionCallback find_context_cb =
473 base::Bind(&ServiceWorkerInternalsUI::FindContext,
474 base::Unretained(this),
475 partition_id,
476 &result_partition);
477 BrowserContext::ForEachStoragePartition(browser_context, find_context_cb);
478 if (!result_partition)
479 return false;
480 *context = static_cast<ServiceWorkerContextWrapper*>(
481 result_partition->GetServiceWorkerContext());
482 return true;
485 void ServiceWorkerInternalsUI::CallServiceWorkerVersionMethod(
486 ServiceWorkerVersionMethod method,
487 const ListValue* args) {
488 DCHECK_CURRENTLY_ON(BrowserThread::UI);
489 int callback_id;
490 const DictionaryValue* cmd_args = NULL;
491 int partition_id;
492 scoped_refptr<ServiceWorkerContextWrapper> context;
493 std::string version_id_string;
494 int64 version_id = 0;
495 if (!args->GetInteger(0, &callback_id) ||
496 !args->GetDictionary(1, &cmd_args) ||
497 !cmd_args->GetInteger("partition_id", &partition_id) ||
498 !GetServiceWorkerContext(partition_id, &context) ||
499 !cmd_args->GetString("version_id", &version_id_string) ||
500 !base::StringToInt64(version_id_string, &version_id)) {
501 return;
504 base::Callback<void(ServiceWorkerStatusCode)> callback =
505 base::Bind(OperationCompleteCallback, AsWeakPtr(), callback_id);
506 CallServiceWorkerVersionMethodWithVersionID(
507 method, context, version_id, callback);
510 void ServiceWorkerInternalsUI::DispatchPushEvent(
511 const ListValue* args) {
512 DCHECK_CURRENTLY_ON(BrowserThread::UI);
513 int callback_id;
514 int partition_id;
515 int64 version_id = 0;
516 std::string version_id_string;
517 const DictionaryValue* cmd_args = NULL;
518 scoped_refptr<ServiceWorkerContextWrapper> context;
519 if (!args->GetInteger(0, &callback_id) ||
520 !args->GetDictionary(1, &cmd_args) ||
521 !cmd_args->GetInteger("partition_id", &partition_id) ||
522 !GetServiceWorkerContext(partition_id, &context) ||
523 !cmd_args->GetString("version_id", &version_id_string) ||
524 !base::StringToInt64(version_id_string, &version_id)) {
525 return;
528 base::Callback<void(ServiceWorkerStatusCode)> callback =
529 base::Bind(OperationCompleteCallback, AsWeakPtr(), callback_id);
530 DispatchPushEventWithVersionID(context, version_id, callback);
533 void ServiceWorkerInternalsUI::InspectWorker(const ListValue* args) {
534 DCHECK_CURRENTLY_ON(BrowserThread::UI);
535 int callback_id;
536 const DictionaryValue* cmd_args = NULL;
537 int process_id = 0;
538 int devtools_agent_route_id = 0;
539 if (!args->GetInteger(0, &callback_id) ||
540 !args->GetDictionary(1, &cmd_args) ||
541 !cmd_args->GetInteger("process_id", &process_id) ||
542 !cmd_args->GetInteger("devtools_agent_route_id",
543 &devtools_agent_route_id)) {
544 return;
546 base::Callback<void(ServiceWorkerStatusCode)> callback =
547 base::Bind(OperationCompleteCallback, AsWeakPtr(), callback_id);
548 scoped_refptr<DevToolsAgentHostImpl> agent_host(
549 ServiceWorkerDevToolsManager::GetInstance()
550 ->GetDevToolsAgentHostForWorker(process_id, devtools_agent_route_id));
551 if (!agent_host.get()) {
552 callback.Run(SERVICE_WORKER_ERROR_NOT_FOUND);
553 return;
555 agent_host->Inspect(web_ui()->GetWebContents()->GetBrowserContext());
556 callback.Run(SERVICE_WORKER_OK);
559 void ServiceWorkerInternalsUI::Unregister(const ListValue* args) {
560 DCHECK_CURRENTLY_ON(BrowserThread::UI);
561 int callback_id;
562 int partition_id;
563 std::string scope_string;
564 const DictionaryValue* cmd_args = NULL;
565 scoped_refptr<ServiceWorkerContextWrapper> context;
566 if (!args->GetInteger(0, &callback_id) ||
567 !args->GetDictionary(1, &cmd_args) ||
568 !cmd_args->GetInteger("partition_id", &partition_id) ||
569 !GetServiceWorkerContext(partition_id, &context) ||
570 !cmd_args->GetString("scope", &scope_string)) {
571 return;
574 base::Callback<void(ServiceWorkerStatusCode)> callback =
575 base::Bind(OperationCompleteCallback, AsWeakPtr(), callback_id);
576 UnregisterWithScope(context, GURL(scope_string), callback);
579 void ServiceWorkerInternalsUI::StartWorker(const ListValue* args) {
580 DCHECK_CURRENTLY_ON(BrowserThread::UI);
581 int callback_id;
582 int partition_id;
583 std::string scope_string;
584 const DictionaryValue* cmd_args = NULL;
585 scoped_refptr<ServiceWorkerContextWrapper> context;
586 if (!args->GetInteger(0, &callback_id) ||
587 !args->GetDictionary(1, &cmd_args) ||
588 !cmd_args->GetInteger("partition_id", &partition_id) ||
589 !GetServiceWorkerContext(partition_id, &context) ||
590 !cmd_args->GetString("scope", &scope_string)) {
591 return;
593 base::Callback<void(ServiceWorkerStatusCode)> callback =
594 base::Bind(OperationCompleteCallback, AsWeakPtr(), callback_id);
595 context->StartServiceWorker(GURL(scope_string), callback);
598 void ServiceWorkerInternalsUI::UnregisterWithScope(
599 scoped_refptr<ServiceWorkerContextWrapper> context,
600 const GURL& scope,
601 const ServiceWorkerInternalsUI::StatusCallback& callback) const {
602 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
603 BrowserThread::PostTask(
604 BrowserThread::IO, FROM_HERE,
605 base::Bind(&ServiceWorkerInternalsUI::UnregisterWithScope,
606 base::Unretained(this), context, scope, callback));
607 return;
610 if (!context->context()) {
611 callback.Run(SERVICE_WORKER_ERROR_ABORT);
612 return;
615 // ServiceWorkerContextWrapper::UnregisterServiceWorker doesn't work here
616 // because that reduces a status code to boolean.
617 context->context()->UnregisterServiceWorker(scope, callback);
620 } // namespace content