Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(153)

Side by Side Diff: content/browser/service_worker/service_worker_internals_ui.cc

Issue 182383008: Create chrome://serviceworker-internals (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 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/values.h"
12 #include "content/browser/service_worker/service_worker_context_core.h"
13 #include "content/browser/service_worker/service_worker_context_wrapper.h"
14 #include "content/browser/service_worker/service_worker_registration.h"
15 #include "content/browser/service_worker/service_worker_version.h"
16 #include "content/public/browser/browser_context.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/browser/storage_partition.h"
19 #include "content/public/browser/web_contents.h"
20 #include "content/public/browser/web_ui.h"
21 #include "content/public/browser/web_ui_data_source.h"
22 #include "content/public/common/url_constants.h"
23 #include "grit/content_resources.h"
24
25 using base::DictionaryValue;
26 using base::FundamentalValue;
27 using base::ListValue;
28 using base::StringValue;
29 using base::Value;
30 using base::WeakPtr;
31
32 namespace content {
33
34 // This class, and the parameters to the *IOTHread methods should be
35 // created on the UI thread, where it will delete itself and
36 // those values.
37 class ServiceWorkerInternalsUI::OperationProxy {
38 public:
39 explicit OperationProxy(const WeakPtr<ServiceWorkerInternalsUI> internals)
40 : internals_(internals) {}
41 ~OperationProxy() {}
42
43 void GetRegistrationsOnIOThread(ServiceWorkerContextWrapper* context,
44 const base::FilePath& context_path);
45 void UnregisterOnIOThread(scoped_ptr<ListValue> original_args,
46 scoped_refptr<ServiceWorkerContextWrapper> context,
47 const GURL& scope);
48 void StartWorkerOnIOThread(scoped_ptr<ListValue> original_args,
49 scoped_refptr<ServiceWorkerContextWrapper> context,
50 const GURL& scope);
51 void StopWorkerOnIOThread(scoped_ptr<ListValue> original_args,
52 scoped_refptr<ServiceWorkerContextWrapper> context,
53 const GURL& scope);
54
55 private:
56 void OnHaveRegistrations(
57 const base::FilePath& context_path,
58 scoped_ptr<std::vector<ServiceWorkerRegistration*> > registrations);
59
60 void OperationComplete(scoped_ptr<ListValue> original_args,
61 ServiceWorkerStatusCode status);
62
63 void StartActiveWorker(
64 scoped_ptr<ListValue> original_args,
65 ServiceWorkerStatusCode status,
66 const scoped_refptr<ServiceWorkerRegistration>& registration);
67
68 void StopActiveWorker(
69 scoped_ptr<ListValue> original_args,
70 ServiceWorkerStatusCode status,
71 const scoped_refptr<ServiceWorkerRegistration>& registration);
72
73 WeakPtr<ServiceWorkerInternalsUI> internals_;
74 };
75
76 ServiceWorkerInternalsUI::ServiceWorkerInternalsUI(WebUI* web_ui)
77 : WebUIController(web_ui) {
78 WebUIDataSource* source =
79 WebUIDataSource::Create(kChromeUIServiceWorkerInternalsHost);
80 source->SetUseJsonJSFormatV2();
81 source->SetJsonPath("strings.js");
82 source->AddResourcePath("serviceworker_internals.js",
83 IDR_SERVICE_WORKER_INTERNALS_JS);
84 source->AddResourcePath("serviceworker_internals.css",
85 IDR_SERVICE_WORKER_INTERNALS_CSS);
86 source->SetDefaultResource(IDR_SERVICE_WORKER_INTERNALS_HTML);
87
88 BrowserContext* browser_context =
89 web_ui->GetWebContents()->GetBrowserContext();
90 WebUIDataSource::Add(browser_context, source);
91
92 web_ui->RegisterMessageCallback(
93 "getAllRegistrations",
94 base::Bind(&ServiceWorkerInternalsUI::GetAllRegistrations,
95 base::Unretained(this)));
96 web_ui->RegisterMessageCallback(
97 "start",
98 base::Bind(&ServiceWorkerInternalsUI::StartWorker,
99 base::Unretained(this)));
100 web_ui->RegisterMessageCallback(
101 "stop",
102 base::Bind(&ServiceWorkerInternalsUI::StopWorker,
103 base::Unretained(this)));
104 web_ui->RegisterMessageCallback(
105 "unregister",
106 base::Bind(&ServiceWorkerInternalsUI::Unregister,
107 base::Unretained(this)));
108 }
109
110 ServiceWorkerInternalsUI::~ServiceWorkerInternalsUI() {}
111
112 void ServiceWorkerInternalsUI::GetAllRegistrations(const ListValue* args) {
113 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
114
115 BrowserContext* browser_context =
116 web_ui()->GetWebContents()->GetBrowserContext();
117
118 // Safe to use base::Unretained(this) because
119 // ForEachStoragePartition is synchronous.
120 BrowserContext::StoragePartitionCallback cb =
121 base::Bind(&ServiceWorkerInternalsUI::AddContextFromStoragePartition,
122 base::Unretained(this));
123 BrowserContext::ForEachStoragePartition(browser_context, cb);
124 }
125
126 void ServiceWorkerInternalsUI::AddContextFromStoragePartition(
127 StoragePartition* partition) {
128 scoped_refptr<ServiceWorkerContextWrapper> context =
129 partition->GetServiceWorkerContext();
130 BrowserThread::PostTask(
131 BrowserThread::IO,
132 FROM_HERE,
133 base::Bind(
134 &ServiceWorkerInternalsUI::OperationProxy::GetRegistrationsOnIOThread,
135 base::Unretained(new OperationProxy(AsWeakPtr())),
136 context,
137 partition->GetPath()));
138 }
139
140 namespace {
141 void FindContext(const base::FilePath& partition_path,
142 StoragePartition** result_partition,
143 scoped_refptr<ServiceWorkerContextWrapper>* result_context,
144 StoragePartition* storage_partition) {
145 if (storage_partition->GetPath() == partition_path) {
146 *result_partition = storage_partition;
147 *result_context = storage_partition->GetServiceWorkerContext();
148 }
149 }
150 } // namespace
151
152 bool ServiceWorkerInternalsUI::GetRegistrationInfo(
153 const ListValue* args,
154 base::FilePath* partition_path,
155 GURL* scope,
156 scoped_refptr<ServiceWorkerContextWrapper>* context) const {
157 base::FilePath::StringType path_string;
158 if (!args->GetString(0, &path_string))
159 return false;
160 *partition_path = base::FilePath(path_string);
161
162 std::string scope_string;
163 if (!args->GetString(1, &scope_string))
164 return false;
165 *scope = GURL(scope_string);
166
167 BrowserContext* browser_context =
168 web_ui()->GetWebContents()->GetBrowserContext();
169
170 StoragePartition* result_partition(NULL);
171 BrowserContext::StoragePartitionCallback cb =
172 base::Bind(&FindContext, *partition_path, &result_partition, context);
173 BrowserContext::ForEachStoragePartition(browser_context, cb);
174
175 if (!result_partition || !(*context))
176 return false;
177
178 return true;
179 }
180
181 void ServiceWorkerInternalsUI::StartWorker(const ListValue* args) {
182 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
183 base::FilePath partition_path;
184 GURL scope;
185 scoped_refptr<ServiceWorkerContextWrapper> context;
186 if (!GetRegistrationInfo(args, &partition_path, &scope, &context))
187 return;
188
189 scoped_ptr<ListValue> args_copy(args->DeepCopy());
190 BrowserThread::PostTask(
191 BrowserThread::IO,
192 FROM_HERE,
193 base::Bind(
194 &ServiceWorkerInternalsUI::OperationProxy::StartWorkerOnIOThread,
195 base::Unretained(new OperationProxy(AsWeakPtr())),
196 base::Passed(&args_copy),
197 context,
198 scope));
199 }
200
201 void ServiceWorkerInternalsUI::StopWorker(const ListValue* args) {
202 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
203 base::FilePath partition_path;
204 GURL scope;
205 scoped_refptr<ServiceWorkerContextWrapper> context;
206 if (!GetRegistrationInfo(args, &partition_path, &scope, &context))
207 return;
208
209 scoped_ptr<ListValue> args_copy(args->DeepCopy());
210 BrowserThread::PostTask(
211 BrowserThread::IO,
212 FROM_HERE,
213 base::Bind(
214 &ServiceWorkerInternalsUI::OperationProxy::StopWorkerOnIOThread,
215 base::Unretained(new OperationProxy(AsWeakPtr())),
216 base::Passed(&args_copy),
217 context,
218 scope));
219 }
220
221 void ServiceWorkerInternalsUI::OperationProxy::UnregisterOnIOThread(
222 scoped_ptr<ListValue> original_args,
223 scoped_refptr<ServiceWorkerContextWrapper> context,
224 const GURL& scope) {
225 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
226 context->context()->UnregisterServiceWorker(
227 scope,
228 0, // render process id?
229 base::Bind(&ServiceWorkerInternalsUI::OperationProxy::OperationComplete,
230 base::Unretained(this),
231 base::Passed(&original_args)));
232 }
233
234 void ServiceWorkerInternalsUI::OperationProxy::OperationComplete(
235 scoped_ptr<ListValue> original_args,
236 ServiceWorkerStatusCode status) {
237 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
238 BrowserThread::PostTask(
239 BrowserThread::UI,
240 FROM_HERE,
241 base::Bind(&ServiceWorkerInternalsUI::OperationProxy::OperationComplete,
242 base::Unretained(this),
243 base::Passed(&original_args),
244 status));
245 return;
246 }
247
248 original_args->Insert(0, new FundamentalValue(static_cast<int>(status)));
249 if (internals_)
250 internals_->web_ui()->CallJavascriptFunction(
251 "serviceworker.onOperationComplete",
252 std::vector<const Value*>(original_args->begin(),
253 original_args->end()));
254 delete this;
255 }
256
257 void ServiceWorkerInternalsUI::OperationProxy::StartWorkerOnIOThread(
258 scoped_ptr<ListValue> original_args,
259 scoped_refptr<ServiceWorkerContextWrapper> context,
260 const GURL& scope) {
261 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
262 // TODO(alecflett): Add support for starting/stopping workers for
263 // pending versions too.
264 context->context()->storage()->FindRegistrationForPattern(
265 scope,
266 base::Bind(&ServiceWorkerInternalsUI::OperationProxy::StartActiveWorker,
267 base::Unretained(this),
268 base::Passed(&original_args)));
269 }
270
271 void ServiceWorkerInternalsUI::OperationProxy::StartActiveWorker(
272 scoped_ptr<ListValue> original_args,
273 ServiceWorkerStatusCode status,
274 const scoped_refptr<ServiceWorkerRegistration>& registration) {
275 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
276 if (status == SERVICE_WORKER_OK) {
277 registration->active_version()->StartWorker(
278 base::Bind(&ServiceWorkerInternalsUI::OperationProxy::OperationComplete,
279 base::Unretained(this),
280 base::Passed(&original_args)));
281 return;
282 }
283
284 OperationComplete(original_args.Pass(), status);
285 }
286
287 void ServiceWorkerInternalsUI::OperationProxy::StopWorkerOnIOThread(
288 scoped_ptr<ListValue> original_args,
289 scoped_refptr<ServiceWorkerContextWrapper> context,
290 const GURL& scope) {
291 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
292 // TODO(alecflett): Add support for starting/stopping workers for
293 // pending versions too.
294 context->context()->storage()->FindRegistrationForPattern(
295 scope,
296 base::Bind(&ServiceWorkerInternalsUI::OperationProxy::StopActiveWorker,
297 base::Unretained(this),
298 base::Passed(&original_args)));
299 }
300
301 void ServiceWorkerInternalsUI::OperationProxy::StopActiveWorker(
302 scoped_ptr<ListValue> original_args,
303 ServiceWorkerStatusCode status,
304 const scoped_refptr<ServiceWorkerRegistration>& registration) {
305 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
306 if (status == SERVICE_WORKER_OK) {
307 registration->active_version()->StopWorker(
308 base::Bind(&ServiceWorkerInternalsUI::OperationProxy::OperationComplete,
309 base::Unretained(this),
310 base::Passed(&original_args)));
311 return;
312 }
313
314 OperationComplete(original_args.Pass(), status);
315 }
316
317 void ServiceWorkerInternalsUI::Unregister(const ListValue* args) {
318 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
319 base::FilePath partition_path;
320 GURL scope;
321 scoped_refptr<ServiceWorkerContextWrapper> context;
322 if (!GetRegistrationInfo(args, &partition_path, &scope, &context))
323 return;
324
325 scoped_ptr<ListValue> args_copy(args->DeepCopy());
326 BrowserThread::PostTask(
327 BrowserThread::IO,
328 FROM_HERE,
329 base::Bind(
330 &ServiceWorkerInternalsUI::OperationProxy::UnregisterOnIOThread,
331 base::Unretained(new OperationProxy(AsWeakPtr())),
332 base::Passed(&args_copy),
333 context,
334 scope));
335 }
336
337 void ServiceWorkerInternalsUI::OperationProxy::GetRegistrationsOnIOThread(
338 ServiceWorkerContextWrapper* context,
339 const base::FilePath& context_path) {
340 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
341
342 context->context()->storage()->FindAllRegistrations(
343 base::Bind(&ServiceWorkerInternalsUI::OperationProxy::OnHaveRegistrations,
344 base::Unretained(this),
345 context_path));
346 }
347
348 namespace {
349 void UpdateVersionInfo(ServiceWorkerVersion* version, DictionaryValue* info) {
350 switch (version->embedded_worker()->status()) {
351 case ServiceWorkerVersion::STOPPED:
352 info->SetString("status", "STOPPED");
353 break;
354 case EmbeddedWorkerInstance::STARTING:
355 info->SetString("status", "STARTING");
356 break;
357 case EmbeddedWorkerInstance::RUNNING:
358 info->SetString("status", "RUNNING");
359 break;
360 case EmbeddedWorkerInstance::STOPPING:
361 info->SetString("status", "STOPPING");
362 break;
363 }
364
365 info->SetInteger("process_id", version->embedded_worker()->process_id());
366 // is this hardware thread or internal thread?
367 info->SetInteger("thread_id", version->embedded_worker()->thread_id());
368 }
369 } // namespace
370
371 void ServiceWorkerInternalsUI::OperationProxy::OnHaveRegistrations(
372 const base::FilePath& context_path,
373 scoped_ptr<std::vector<ServiceWorkerRegistration*> > registrations) {
michaeln 2014/03/04 00:25:47 Don't we need a different representation for this
374 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
375 BrowserThread::PostTask(
376 BrowserThread::UI,
377 FROM_HERE,
378 base::Bind(
379 &ServiceWorkerInternalsUI::OperationProxy::OnHaveRegistrations,
380 base::Unretained(this),
381 context_path,
382 base::Passed(&registrations)));
383 return;
384 }
385
386 ListValue result;
387 for (std::vector<ServiceWorkerRegistration*>::const_iterator it =
388 registrations->begin();
389 it != registrations->end();
390 ++it) {
391 const ServiceWorkerRegistration* registration = *it;
392 DictionaryValue* registration_info = new DictionaryValue();
393 registration_info->SetString("scope", registration->pattern().spec());
394 registration_info->SetString("script_url",
395 registration->script_url().spec());
396
397 if (registration->active_version()) {
398 DictionaryValue* active_info = new DictionaryValue();
399 UpdateVersionInfo(registration->active_version(), active_info);
400 registration_info->Set("active", active_info);
401 }
402
403 if (registration->pending_version()) {
404 DictionaryValue* pending_info = new DictionaryValue();
405 UpdateVersionInfo(registration->active_version(), pending_info);
406 registration_info->Set("pending", pending_info);
407 }
408
409 result.Append(registration_info);
410 }
411
412 if (internals_)
413 internals_->web_ui()->CallJavascriptFunction(
414 "serviceworker.onPartitionData",
415 result,
416 StringValue(context_path.value()));
417 delete this;
418 }
419
420 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/service_worker/service_worker_internals_ui.h ('k') | content/browser/service_worker/service_worker_storage.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698