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
OperationCompleteCallback(WeakPtr<ServiceWorkerInternalsUI> internals,int callback_id,ServiceWorkerStatusCode status)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
CallServiceWorkerVersionMethodWithVersionID(ServiceWorkerInternalsUI::ServiceWorkerVersionMethod method,scoped_refptr<ServiceWorkerContextWrapper> context,int64 version_id,const ServiceWorkerInternalsUI::StatusCallback & callback)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
DispatchPushEventWithVersionID(scoped_refptr<ServiceWorkerContextWrapper> context,int64 version_id,const ServiceWorkerInternalsUI::StatusCallback & callback)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
UnregisterWithScope(scoped_refptr<ServiceWorkerContextWrapper> context,const GURL & scope,const ServiceWorkerInternalsUI::StatusCallback & callback)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
WorkerStarted(const scoped_refptr<ServiceWorkerRegistration> & registration,const ServiceWorkerInternalsUI::StatusCallback & callback,ServiceWorkerStatusCode status)125 void WorkerStarted(const scoped_refptr<ServiceWorkerRegistration>& registration,
126 const ServiceWorkerInternalsUI::StatusCallback& callback,
127 ServiceWorkerStatusCode status) {
128 callback.Run(status);
129 }
130
StartActiveWorker(const ServiceWorkerInternalsUI::StatusCallback & callback,ServiceWorkerStatusCode status,const scoped_refptr<ServiceWorkerRegistration> & registration)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
FindRegistrationForPattern(scoped_refptr<ServiceWorkerContextWrapper> context,const GURL & scope,const ServiceWorkerStorage::FindRegistrationCallback callback)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
UpdateVersionInfo(const ServiceWorkerVersionInfo & version,DictionaryValue * info)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::ACTIVE:
193 info->SetString("status", "ACTIVE");
194 break;
195 case ServiceWorkerVersion::DEACTIVATED:
196 info->SetString("status", "DEACTIVATED");
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
GetRegistrationListValue(const std::vector<ServiceWorkerRegistrationInfo> & registrations)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
GetVersionListValue(const std::vector<ServiceWorkerVersionInfo> & versions)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
GetRegistrationsOnIOThread(scoped_refptr<ServiceWorkerContextWrapper> context,base::Callback<void (const std::vector<ServiceWorkerRegistrationInfo> &)> callback)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
OnStoredRegistrations(scoped_refptr<ServiceWorkerContextWrapper> context,base::Callback<void (const std::vector<ServiceWorkerRegistrationInfo> &,const std::vector<ServiceWorkerVersionInfo> &,const std::vector<ServiceWorkerRegistrationInfo> &)> callback,const std::vector<ServiceWorkerRegistrationInfo> & stored_registrations)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
OnAllRegistrations(WeakPtr<ServiceWorkerInternalsUI> internals,int partition_id,const base::FilePath & context_path,const std::vector<ServiceWorkerRegistrationInfo> & live_registrations,const std::vector<ServiceWorkerVersionInfo> & live_versions,const std::vector<ServiceWorkerRegistrationInfo> & stored_registrations)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:
PartitionObserver(int partition_id,WebUI * web_ui)301 PartitionObserver(int partition_id, WebUI* web_ui)
302 : partition_id_(partition_id), web_ui_(web_ui) {}
~PartitionObserver()303 virtual ~PartitionObserver() {}
304 // ServiceWorkerContextObserver overrides:
OnWorkerStarted(int64 version_id,int process_id,int thread_id)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 }
OnWorkerStopped(int64 version_id,int process_id,int thread_id)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 }
OnVersionStateChanged(int64 version_id)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 }
OnErrorReported(int64 version_id,int process_id,int thread_id,const ErrorInfo & info)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 }
OnReportConsoleMessage(int64 version_id,int process_id,int thread_id,const ConsoleMessage & message)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 }
OnRegistrationStored(const GURL & pattern)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 }
OnRegistrationDeleted(const GURL & pattern)378 virtual void OnRegistrationDeleted(const GURL& pattern) OVERRIDE {
379 web_ui_->CallJavascriptFunction("serviceworker.onRegistrationDeleted",
380 StringValue(pattern.spec()));
381 }
partition_id() const382 int partition_id() const { return partition_id_; }
383
384 private:
385 const int partition_id_;
386 WebUI* const web_ui_;
387 };
388
ServiceWorkerInternalsUI(WebUI * web_ui)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
~ServiceWorkerInternalsUI()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
GetOptions(const ListValue * args)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
SetOption(const ListValue * args)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
GetAllRegistrations(const ListValue * args)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
AddContextFromStoragePartition(StoragePartition * partition)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 BrowserThread::PostTask(
504 BrowserThread::IO,
505 FROM_HERE,
506 base::Bind(GetRegistrationsOnIOThread,
507 context,
508 base::Bind(OnStoredRegistrations,
509 context,
510 base::Bind(OnAllRegistrations,
511 AsWeakPtr(),
512 partition_id,
513 partition->GetPath()))));
514 }
515
RemoveObserverFromStoragePartition(StoragePartition * partition)516 void ServiceWorkerInternalsUI::RemoveObserverFromStoragePartition(
517 StoragePartition* partition) {
518 scoped_ptr<PartitionObserver> observer(
519 observers_.take_and_erase(reinterpret_cast<uintptr_t>(partition)));
520 if (!observer.get())
521 return;
522 scoped_refptr<ServiceWorkerContextWrapper> context =
523 static_cast<ServiceWorkerContextWrapper*>(
524 partition->GetServiceWorkerContext());
525 context->RemoveObserver(observer.get());
526 }
527
FindContext(int partition_id,StoragePartition ** result_partition,StoragePartition * storage_partition) const528 void ServiceWorkerInternalsUI::FindContext(
529 int partition_id,
530 StoragePartition** result_partition,
531 StoragePartition* storage_partition) const {
532 PartitionObserver* observer =
533 observers_.get(reinterpret_cast<uintptr_t>(storage_partition));
534 if (observer && partition_id == observer->partition_id()) {
535 *result_partition = storage_partition;
536 }
537 }
538
GetServiceWorkerContext(int partition_id,scoped_refptr<ServiceWorkerContextWrapper> * context) const539 bool ServiceWorkerInternalsUI::GetServiceWorkerContext(
540 int partition_id,
541 scoped_refptr<ServiceWorkerContextWrapper>* context) const {
542 BrowserContext* browser_context =
543 web_ui()->GetWebContents()->GetBrowserContext();
544 StoragePartition* result_partition(NULL);
545 BrowserContext::StoragePartitionCallback find_context_cb =
546 base::Bind(&ServiceWorkerInternalsUI::FindContext,
547 base::Unretained(this),
548 partition_id,
549 &result_partition);
550 BrowserContext::ForEachStoragePartition(browser_context, find_context_cb);
551 if (!result_partition)
552 return false;
553 *context = static_cast<ServiceWorkerContextWrapper*>(
554 result_partition->GetServiceWorkerContext());
555 return true;
556 }
557
CallServiceWorkerVersionMethod(ServiceWorkerVersionMethod method,const ListValue * args)558 void ServiceWorkerInternalsUI::CallServiceWorkerVersionMethod(
559 ServiceWorkerVersionMethod method,
560 const ListValue* args) {
561 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
562 int callback_id;
563 int partition_id;
564 int64 version_id;
565 std::string version_id_string;
566 const DictionaryValue* cmd_args = NULL;
567 scoped_refptr<ServiceWorkerContextWrapper> context;
568 if (!args->GetInteger(0, &callback_id) ||
569 !args->GetDictionary(1, &cmd_args) ||
570 !cmd_args->GetInteger("partition_id", &partition_id) ||
571 !GetServiceWorkerContext(partition_id, &context) ||
572 !cmd_args->GetString("version_id", &version_id_string) ||
573 !base::StringToInt64(version_id_string, &version_id)) {
574 return;
575 }
576
577 base::Callback<void(ServiceWorkerStatusCode)> callback =
578 base::Bind(OperationCompleteCallback, AsWeakPtr(), callback_id);
579 CallServiceWorkerVersionMethodWithVersionID(
580 method, context, version_id, callback);
581 }
582
DispatchPushEvent(const ListValue * args)583 void ServiceWorkerInternalsUI::DispatchPushEvent(
584 const ListValue* args) {
585 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
586 int callback_id;
587 int partition_id;
588 int64 version_id;
589 std::string version_id_string;
590 const DictionaryValue* cmd_args = NULL;
591 scoped_refptr<ServiceWorkerContextWrapper> context;
592 if (!args->GetInteger(0, &callback_id) ||
593 !args->GetDictionary(1, &cmd_args) ||
594 !cmd_args->GetInteger("partition_id", &partition_id) ||
595 !GetServiceWorkerContext(partition_id, &context) ||
596 !cmd_args->GetString("version_id", &version_id_string) ||
597 !base::StringToInt64(version_id_string, &version_id)) {
598 return;
599 }
600
601 base::Callback<void(ServiceWorkerStatusCode)> callback =
602 base::Bind(OperationCompleteCallback, AsWeakPtr(), callback_id);
603 DispatchPushEventWithVersionID(context, version_id, callback);
604 }
605
InspectWorker(const ListValue * args)606 void ServiceWorkerInternalsUI::InspectWorker(const ListValue* args) {
607 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
608 int callback_id;
609 int process_id;
610 int devtools_agent_route_id;
611 const DictionaryValue* cmd_args = NULL;
612 scoped_refptr<ServiceWorkerContextWrapper> context;
613 if (!args->GetInteger(0, &callback_id) ||
614 !args->GetDictionary(1, &cmd_args) ||
615 !cmd_args->GetInteger("process_id", &process_id) ||
616 !cmd_args->GetInteger("devtools_agent_route_id",
617 &devtools_agent_route_id)) {
618 return;
619 }
620 base::Callback<void(ServiceWorkerStatusCode)> callback =
621 base::Bind(OperationCompleteCallback, AsWeakPtr(), callback_id);
622 scoped_refptr<DevToolsAgentHost> agent_host(
623 EmbeddedWorkerDevToolsManager::GetInstance()
624 ->GetDevToolsAgentHostForWorker(process_id, devtools_agent_route_id));
625 if (!agent_host) {
626 callback.Run(SERVICE_WORKER_ERROR_NOT_FOUND);
627 return;
628 }
629 DevToolsManagerImpl::GetInstance()->Inspect(
630 web_ui()->GetWebContents()->GetBrowserContext(), agent_host.get());
631 callback.Run(SERVICE_WORKER_OK);
632 }
633
Unregister(const ListValue * args)634 void ServiceWorkerInternalsUI::Unregister(const ListValue* args) {
635 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
636 int callback_id;
637 int partition_id;
638 std::string scope_string;
639 const DictionaryValue* cmd_args = NULL;
640 scoped_refptr<ServiceWorkerContextWrapper> context;
641 if (!args->GetInteger(0, &callback_id) ||
642 !args->GetDictionary(1, &cmd_args) ||
643 !cmd_args->GetInteger("partition_id", &partition_id) ||
644 !GetServiceWorkerContext(partition_id, &context) ||
645 !cmd_args->GetString("scope", &scope_string)) {
646 return;
647 }
648
649 base::Callback<void(ServiceWorkerStatusCode)> callback =
650 base::Bind(OperationCompleteCallback, AsWeakPtr(), callback_id);
651 UnregisterWithScope(context, GURL(scope_string), callback);
652 }
653
StartWorker(const ListValue * args)654 void ServiceWorkerInternalsUI::StartWorker(const ListValue* args) {
655 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
656 int callback_id;
657 int partition_id;
658 std::string scope_string;
659 const DictionaryValue* cmd_args = NULL;
660 scoped_refptr<ServiceWorkerContextWrapper> context;
661 if (!args->GetInteger(0, &callback_id) ||
662 !args->GetDictionary(1, &cmd_args) ||
663 !cmd_args->GetInteger("partition_id", &partition_id) ||
664 !GetServiceWorkerContext(partition_id, &context) ||
665 !cmd_args->GetString("scope", &scope_string)) {
666 return;
667 }
668
669 base::Callback<void(ServiceWorkerStatusCode)> callback =
670 base::Bind(OperationCompleteCallback, AsWeakPtr(), callback_id);
671 FindRegistrationForPattern(
672 context, GURL(scope_string), base::Bind(StartActiveWorker, callback));
673 }
674
675 } // namespace content
676