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

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: Fix nits 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 proxies calls to the ServiceWorker APIs on the IO
35 // thread, and then calls back JavaScript on the UI thread.
36 class ServiceWorkerInternalsUI::OperationProxy
37 : public base::RefCountedThreadSafe<
38 ServiceWorkerInternalsUI::OperationProxy> {
39 public:
40 OperationProxy(const WeakPtr<ServiceWorkerInternalsUI> internals,
41 scoped_ptr<ListValue> original_args)
42 : internals_(internals), original_args_(original_args.Pass()) {}
43
44 void GetRegistrationsOnIOThread(ServiceWorkerContextWrapper* context,
45 const base::FilePath& context_path);
46 void UnregisterOnIOThread(scoped_refptr<ServiceWorkerContextWrapper> context,
47 const GURL& scope);
48 void StartWorkerOnIOThread(scoped_refptr<ServiceWorkerContextWrapper> context,
49 const GURL& scope);
50 void StopWorkerOnIOThread(scoped_refptr<ServiceWorkerContextWrapper> context,
51 const GURL& scope);
52
53 private:
54 friend class base::RefCountedThreadSafe<OperationProxy>;
55 ~OperationProxy() {}
56 void OnHaveRegistrations(
57 const base::FilePath& context_path,
58 const std::vector<ServiceWorkerRegistrationInfo>& registrations);
59
60 void OperationComplete(ServiceWorkerStatusCode status);
61
62 void StartActiveWorker(
63 ServiceWorkerStatusCode status,
64 const scoped_refptr<ServiceWorkerRegistration>& registration);
65
66 void StopActiveWorker(
67 ServiceWorkerStatusCode status,
68 const scoped_refptr<ServiceWorkerRegistration>& registration);
69
70 WeakPtr<ServiceWorkerInternalsUI> internals_;
71 scoped_ptr<ListValue> original_args_;
72 };
73
74 ServiceWorkerInternalsUI::ServiceWorkerInternalsUI(WebUI* web_ui)
75 : WebUIController(web_ui) {
76 WebUIDataSource* source =
77 WebUIDataSource::Create(kChromeUIServiceWorkerInternalsHost);
78 source->SetUseJsonJSFormatV2();
79 source->SetJsonPath("strings.js");
80 source->AddResourcePath("serviceworker_internals.js",
81 IDR_SERVICE_WORKER_INTERNALS_JS);
82 source->AddResourcePath("serviceworker_internals.css",
83 IDR_SERVICE_WORKER_INTERNALS_CSS);
84 source->SetDefaultResource(IDR_SERVICE_WORKER_INTERNALS_HTML);
85
86 BrowserContext* browser_context =
87 web_ui->GetWebContents()->GetBrowserContext();
88 WebUIDataSource::Add(browser_context, source);
89
90 web_ui->RegisterMessageCallback(
91 "getAllRegistrations",
92 base::Bind(&ServiceWorkerInternalsUI::GetAllRegistrations,
93 base::Unretained(this)));
94 web_ui->RegisterMessageCallback(
95 "start",
96 base::Bind(&ServiceWorkerInternalsUI::StartWorker,
97 base::Unretained(this)));
98 web_ui->RegisterMessageCallback(
99 "stop",
100 base::Bind(&ServiceWorkerInternalsUI::StopWorker,
101 base::Unretained(this)));
102 web_ui->RegisterMessageCallback(
103 "unregister",
104 base::Bind(&ServiceWorkerInternalsUI::Unregister,
105 base::Unretained(this)));
106 }
107
108 ServiceWorkerInternalsUI::~ServiceWorkerInternalsUI() {}
109
110 void ServiceWorkerInternalsUI::GetAllRegistrations(const ListValue* args) {
111 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
112
113 BrowserContext* browser_context =
114 web_ui()->GetWebContents()->GetBrowserContext();
115
116 // Safe to use base::Unretained(this) because
117 // ForEachStoragePartition is synchronous.
118 BrowserContext::StoragePartitionCallback cb =
119 base::Bind(&ServiceWorkerInternalsUI::AddContextFromStoragePartition,
120 base::Unretained(this));
121 BrowserContext::ForEachStoragePartition(browser_context, cb);
122 }
123
124 void ServiceWorkerInternalsUI::AddContextFromStoragePartition(
125 StoragePartition* partition) {
126 scoped_refptr<ServiceWorkerContextWrapper> context =
127 partition->GetServiceWorkerContext();
128 BrowserThread::PostTask(
129 BrowserThread::IO,
130 FROM_HERE,
131 base::Bind(
132 &ServiceWorkerInternalsUI::OperationProxy::GetRegistrationsOnIOThread,
133 new OperationProxy(AsWeakPtr(), scoped_ptr<ListValue>()),
134 context,
135 partition->GetPath()));
136 }
137
138 namespace {
139 void FindContext(const base::FilePath& partition_path,
140 StoragePartition** result_partition,
141 scoped_refptr<ServiceWorkerContextWrapper>* result_context,
142 StoragePartition* storage_partition) {
143 if (storage_partition->GetPath() == partition_path) {
144 *result_partition = storage_partition;
145 *result_context = storage_partition->GetServiceWorkerContext();
146 }
147 }
148 } // namespace
149
150 bool ServiceWorkerInternalsUI::GetRegistrationInfo(
151 const ListValue* args,
152 base::FilePath* partition_path,
153 GURL* scope,
154 scoped_refptr<ServiceWorkerContextWrapper>* context) const {
155 base::FilePath::StringType path_string;
156 if (!args->GetString(0, &path_string))
157 return false;
158 *partition_path = base::FilePath(path_string);
159
160 std::string scope_string;
161 if (!args->GetString(1, &scope_string))
162 return false;
163 *scope = GURL(scope_string);
164
165 BrowserContext* browser_context =
166 web_ui()->GetWebContents()->GetBrowserContext();
167
168 StoragePartition* result_partition(NULL);
169 BrowserContext::StoragePartitionCallback cb =
170 base::Bind(&FindContext, *partition_path, &result_partition, context);
171 BrowserContext::ForEachStoragePartition(browser_context, cb);
172
173 if (!result_partition || !(*context))
174 return false;
175
176 return true;
177 }
178
179 void ServiceWorkerInternalsUI::Unregister(const ListValue* args) {
180 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
181 base::FilePath partition_path;
182 GURL scope;
183 scoped_refptr<ServiceWorkerContextWrapper> context;
184 if (!GetRegistrationInfo(args, &partition_path, &scope, &context))
185 return;
186
187 scoped_ptr<ListValue> args_copy(args->DeepCopy());
188 BrowserThread::PostTask(
189 BrowserThread::IO,
190 FROM_HERE,
191 base::Bind(
192 &ServiceWorkerInternalsUI::OperationProxy::UnregisterOnIOThread,
193 new OperationProxy(AsWeakPtr(), args_copy.Pass()),
194 context,
195 scope));
196 }
197
198 void ServiceWorkerInternalsUI::StartWorker(const ListValue* args) {
199 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
200 base::FilePath partition_path;
201 GURL scope;
202 scoped_refptr<ServiceWorkerContextWrapper> context;
203 if (!GetRegistrationInfo(args, &partition_path, &scope, &context))
204 return;
205
206 scoped_ptr<ListValue> args_copy(args->DeepCopy());
207 BrowserThread::PostTask(
208 BrowserThread::IO,
209 FROM_HERE,
210 base::Bind(
211 &ServiceWorkerInternalsUI::OperationProxy::StartWorkerOnIOThread,
212 new OperationProxy(AsWeakPtr(), args_copy.Pass()),
213 context,
214 scope));
215 }
216
217 void ServiceWorkerInternalsUI::StopWorker(const ListValue* args) {
218 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
219 base::FilePath partition_path;
220 GURL scope;
221 scoped_refptr<ServiceWorkerContextWrapper> context;
222 if (!GetRegistrationInfo(args, &partition_path, &scope, &context))
223 return;
224
225 scoped_ptr<ListValue> args_copy(args->DeepCopy());
226 BrowserThread::PostTask(
227 BrowserThread::IO,
228 FROM_HERE,
229 base::Bind(
230 &ServiceWorkerInternalsUI::OperationProxy::StopWorkerOnIOThread,
231 new OperationProxy(AsWeakPtr(), args_copy.Pass()),
232 context,
233 scope));
234 }
235
236 void ServiceWorkerInternalsUI::OperationProxy::GetRegistrationsOnIOThread(
237 ServiceWorkerContextWrapper* context,
238 const base::FilePath& context_path) {
239 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
240
241 context->context()->storage()->GetAllRegistrations(
242 base::Bind(&ServiceWorkerInternalsUI::OperationProxy::OnHaveRegistrations,
243 this,
244 context_path));
245 }
246
247 void ServiceWorkerInternalsUI::OperationProxy::UnregisterOnIOThread(
248 scoped_refptr<ServiceWorkerContextWrapper> context,
249 const GURL& scope) {
250 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
251 context->context()->UnregisterServiceWorker(
252 scope,
253 0, // render process id?
254 base::Bind(&ServiceWorkerInternalsUI::OperationProxy::OperationComplete,
255 this));
256 }
257
258 void ServiceWorkerInternalsUI::OperationProxy::StartWorkerOnIOThread(
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 this));
268 }
269
270 void ServiceWorkerInternalsUI::OperationProxy::StopWorkerOnIOThread(
271 scoped_refptr<ServiceWorkerContextWrapper> context,
272 const GURL& scope) {
273 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
274 // TODO(alecflett): Add support for starting/stopping workers for
275 // pending versions too.
276 context->context()->storage()->FindRegistrationForPattern(
277 scope,
278 base::Bind(&ServiceWorkerInternalsUI::OperationProxy::StopActiveWorker,
279 this));
280 }
281
282 namespace {
283 void UpdateVersionInfo(const ServiceWorkerVersionInfo& version,
284 DictionaryValue* info) {
285 switch (version.status) {
286 case ServiceWorkerVersion::STOPPED:
287 info->SetString("status", "STOPPED");
288 break;
289 case EmbeddedWorkerInstance::STARTING:
290 info->SetString("status", "STARTING");
291 break;
292 case EmbeddedWorkerInstance::RUNNING:
293 info->SetString("status", "RUNNING");
294 break;
295 case EmbeddedWorkerInstance::STOPPING:
296 info->SetString("status", "STOPPING");
297 break;
298 }
299
300 info->SetInteger("process_id", version.process_id);
301 // is this hardware thread or internal thread?
kinuko 2014/03/07 02:19:09 (Will we keep this comment?) This is internal thre
302 info->SetInteger("thread_id", version.thread_id);
303 }
304 } // namespace
305
306 void ServiceWorkerInternalsUI::OperationProxy::OnHaveRegistrations(
307 const base::FilePath& context_path,
308 const std::vector<ServiceWorkerRegistrationInfo>& registrations) {
309 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
310 BrowserThread::PostTask(
311 BrowserThread::UI,
312 FROM_HERE,
313 base::Bind(
314 &ServiceWorkerInternalsUI::OperationProxy::OnHaveRegistrations,
315 this,
316 context_path,
317 registrations));
318 return;
319 }
320
321 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
322 ListValue result;
323 for (std::vector<ServiceWorkerRegistrationInfo>::const_iterator it =
324 registrations.begin();
325 it != registrations.end();
326 ++it) {
327 const ServiceWorkerRegistrationInfo& registration = *it;
328 DictionaryValue* registration_info = new DictionaryValue();
329 registration_info->SetString("scope", registration.pattern.spec());
330 registration_info->SetString("script_url", registration.script_url.spec());
331
332 if (!registration.active_version.is_null) {
333 DictionaryValue* active_info = new DictionaryValue();
334 UpdateVersionInfo(registration.active_version, active_info);
335 registration_info->Set("active", active_info);
336 }
337
338 if (!registration.pending_version.is_null) {
339 DictionaryValue* pending_info = new DictionaryValue();
340 UpdateVersionInfo(registration.active_version, pending_info);
341 registration_info->Set("pending", pending_info);
342 }
343
344 result.Append(registration_info);
345 }
346
347 if (internals_ && !result.empty())
348 internals_->web_ui()->CallJavascriptFunction(
349 "serviceworker.onPartitionData",
350 result,
351 StringValue(context_path.value()));
352 }
353
354 void ServiceWorkerInternalsUI::OperationProxy::OperationComplete(
355 ServiceWorkerStatusCode status) {
356 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
357 BrowserThread::PostTask(
358 BrowserThread::UI,
359 FROM_HERE,
360 base::Bind(&ServiceWorkerInternalsUI::OperationProxy::OperationComplete,
361 this,
362 status));
363 return;
364 }
365
366 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
367 original_args_->Insert(0, new FundamentalValue(static_cast<int>(status)));
368 if (internals_)
369 internals_->web_ui()->CallJavascriptFunction(
370 "serviceworker.onOperationComplete",
371 std::vector<const Value*>(original_args_->begin(),
372 original_args_->end()));
373 }
374
375 void ServiceWorkerInternalsUI::OperationProxy::StartActiveWorker(
376 ServiceWorkerStatusCode status,
377 const scoped_refptr<ServiceWorkerRegistration>& registration) {
378 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
379 if (status == SERVICE_WORKER_OK) {
380 registration->active_version()->StartWorker(base::Bind(
381 &ServiceWorkerInternalsUI::OperationProxy::OperationComplete, this));
382 return;
383 }
384
385 OperationComplete(status);
386 }
387
388 void ServiceWorkerInternalsUI::OperationProxy::StopActiveWorker(
389 ServiceWorkerStatusCode status,
390 const scoped_refptr<ServiceWorkerRegistration>& registration) {
391 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
392 if (status == SERVICE_WORKER_OK) {
393 registration->active_version()->StopWorker(base::Bind(
394 &ServiceWorkerInternalsUI::OperationProxy::OperationComplete, this));
395 return;
396 }
397
398 OperationComplete(status);
399 }
400
401 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698