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

Side by Side Diff: chrome/browser/ui/webui/quota_internals_ui.cc

Issue 7084024: Add chrome://quota-internals/ (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Reflect comments, move QuotaInternals{MessageHandler,Proxy} to .cc. Created 9 years, 6 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
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/ui/webui/quota_internals_ui.h" 5 #include "chrome/browser/ui/webui/quota_internals_ui.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <string> 8 #include <string>
9 9
10 #include "base/values.h"
10 #include "chrome/browser/profiles/profile.h" 11 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/common/url_constants.h" 12 #include "chrome/common/url_constants.h"
12 #include "content/browser/tab_contents/tab_contents.h" 13 #include "content/browser/tab_contents/tab_contents.h"
13 #include "grit/quota_internals_resources.h" 14 #include "grit/quota_internals_resources.h"
15 #include "net/base/net_util.h"
14 #include "ui/base/resource/resource_bundle.h" 16 #include "ui/base/resource/resource_bundle.h"
15 17
18 namespace {
Evan Stade 2011/06/01 01:15:04 insert blank line
tzik 2011/06/03 16:01:19 Done.
19 template<typename T>
20 std::string ToString(const T& v) {
21 std::ostringstream out;
22 out << v;
23 return out.str();
24 }
25
26 std::string StorageTypeToString(quota::StorageType type) {
27 switch (type) {
28 case quota::kStorageTypeTemporary:
29 return "temporary";
30 case quota::kStorageTypePersistent:
31 return "persistent";
32 default:
33 return "unknown";
34 }
35 }
Evan Stade 2011/06/01 01:15:04 insert blank line
tzik 2011/06/03 16:01:19 Done.
36 } // anonymous namespace
37
38 namespace quota_internals {
39
40 class GlobalData {
41 public:
42 GlobalData(quota::StorageType type,
43 int64 usage,
44 int64 unlimited_usage,
45 int64 quota)
46 : type_(type),
47 usage_(usage),
48 unlimited_usage_(unlimited_usage),
49 quota_(quota) {
50 }
51
52 Value* NewValue() const {
53 scoped_ptr<DictionaryValue> dict(new DictionaryValue);
54 dict->SetString("type", StorageTypeToString(type_));
55 if (usage_ >= 0)
56 dict->SetString("usage", ToString(usage_));
57 if (unlimited_usage_ >= 0)
58 dict->SetString("unlimited_usage", ToString(unlimited_usage_));
59 if (quota_ >= 0)
60 dict->SetString("quota", ToString(quota_));
61 return dict.release();
62 }
63
64 private:
65 quota::StorageType type_;
66 int64 usage_;
67 int64 unlimited_usage_;
68 int64 quota_;
69 };
70
71 class HostData {
72 public:
73 HostData(const std::string& host,
74 quota::StorageType type,
75 int64 usage,
76 int64 quota)
77 : host_(host),
78 type_(type),
79 usage_(usage),
80 quota_(quota) {
81 }
82
83 Value* NewValue() const {
84 scoped_ptr<DictionaryValue> dict(new DictionaryValue);
85 DCHECK(!host_.empty());
86 dict->SetString("host", host_);
87 dict->SetString("type", StorageTypeToString(type_));
88 if (usage_ >= 0)
89 dict->SetString("usage", ToString(usage_));
90 if (quota_ >= 0)
91 dict->SetString("quota", ToString(quota_));
92 return dict.release();
93 }
94
95 private:
96 std::string host_;
97 quota::StorageType type_;
98 int64 usage_;
99 int64 quota_;
100 };
101
102 struct OriginData {
103 public:
104 OriginData(const GURL& origin,
105 quota::StorageType type,
106 int in_use,
107 int used_count,
108 base::Time last_access_time)
109 : origin_(origin),
110 type_(type),
111 host_(net::GetHostOrSpecFromURL(origin)),
112 in_use_(in_use),
113 used_count_(used_count),
114 last_access_time_(last_access_time) {
115 }
116
117 Value* NewValue() const {
118 scoped_ptr<DictionaryValue> dict(new DictionaryValue);
119 DCHECK(!origin_.is_empty());
120 DCHECK(!host_.empty());
121 dict->SetString("origin", origin_.spec());
122 dict->SetString("type", StorageTypeToString(type_));
123 dict->SetString("host", ToString(host_));
124 if (in_use_ >= 0)
125 dict->SetBoolean("in_use", in_use_ ? true : false);
126 if (used_count_ >= 0)
127 dict->SetInteger("used_count", used_count_);
128 if (!last_access_time_.is_null())
129 dict->SetDouble("last_access_time", last_access_time_.ToDoubleT());
130 return dict.release();
131 }
132
133 private:
134 GURL origin_;
135 quota::StorageType type_;
136 std::string host_;
137 int in_use_;
138 int used_count_;
139 base::Time last_access_time_;
140 };
141
142 typedef std::map<std::string, std::string> Statistics;
143
144 class QuotaInternalsProxy;
145
146 class QuotaInternalsHTMLSource : public ChromeURLDataManager::DataSource {
147 public:
148 QuotaInternalsHTMLSource()
149 : DataSource(chrome::kChromeUIQuotaInternalsHost,
150 MessageLoop::current()) {
151 }
152
153 virtual void StartDataRequest(const std::string& path,
154 bool is_incognito,
155 int request_id) OVERRIDE {
156 base::StringPiece html(
157 ResourceBundle::GetSharedInstance().GetRawDataResource(
158 IDR_QUOTA_INTERNALS_INDEX_HTML));
159
160 scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
161 html_bytes->data.resize(html.size());
162 std::copy(html.data(), html.data() + html.size(),
163 html_bytes->data.begin());
164 SendResponse(request_id, html_bytes);
165 return;
166 }
167
168 virtual std::string GetMimeType(const std::string&) const OVERRIDE {
169 return "text/html";
170 }
171
172 private:
173 virtual ~QuotaInternalsHTMLSource() {}
174 DISALLOW_COPY_AND_ASSIGN(QuotaInternalsHTMLSource);
175 };
176
177 class QuotaInternalsMessageHandler : public WebUIMessageHandler {
Evan Stade 2011/06/01 01:15:04 this class needs to go in its own file
tzik 2011/06/03 16:01:19 Done. Should I move QuotaInternalsProxy to another
178 public:
179 QuotaInternalsMessageHandler() {}
180
181 virtual ~QuotaInternalsMessageHandler();
182
183 virtual void RegisterMessages() OVERRIDE {
184 DCHECK(web_ui_);
185 web_ui_->RegisterMessageCallback(
186 "requestData",
187 NewCallback(this, &QuotaInternalsMessageHandler::OnRequestData));
188 }
189
190 void ReportAvailableSpace(int64 available_space) {
191 scoped_ptr<Value> avail(
192 Value::CreateStringValue(ToString(available_space)));
193 SendMessage("AvailableSpaceUpdated", *avail.get());
194 }
195
196 void ReportGlobalData(const GlobalData& data) {
197 scoped_ptr<Value> value(data.NewValue());
198 SendMessage("GlobalDataUpdated", *value);
199 }
200
201 void ReportHostData(const std::vector<HostData>& hosts) {
202 ListValue values;
203 typedef std::vector<HostData>::const_iterator iterator;
204 for (iterator itr(hosts.begin()), end(hosts.end());
205 itr != end; ++itr)
Evan Stade 2011/06/01 01:15:04 need curlies
tzik 2011/06/03 16:01:19 Done.
206 values.Append(itr->NewValue());
Evan Stade 2011/06/01 01:15:04 newline
tzik 2011/06/03 16:01:19 Done.
207 SendMessage("HostDataUpdated", values);
208 }
209
210 void ReportOriginData(const std::vector<OriginData>& origins) {
211 ListValue origins_value;
212 typedef std::vector<OriginData>::const_iterator iterator;
213 for (iterator itr(origins.begin()), end(origins.end());
214 itr != end; ++itr)
Evan Stade 2011/06/01 01:15:04 need curlies
tzik 2011/06/03 16:01:19 Done.
215 origins_value.Append(itr->NewValue());
216
217 SendMessage("OriginDataUpdated", origins_value);
218 }
219
220 void ReportStatistics(const Statistics& stats) {
221 DictionaryValue dict;
222 typedef Statistics::const_iterator iterator;
223 for (iterator itr(stats.begin()), end(stats.end());
224 itr != end; ++itr)
Evan Stade 2011/06/01 01:15:04 need curlies
tzik 2011/06/03 16:01:19 Done.
225 dict.SetString(itr->first, itr->second);
Evan Stade 2011/06/01 01:15:04 newline
tzik 2011/06/03 16:01:19 Done.
226 SendMessage("StatisticsUpdated", dict);
227 }
228
229 private:
230 void OnRequestData(const ListValue*);
231
232 void SendMessage(const std::string& message, const Value& value) {
233 scoped_ptr<Value> message_data(Value::CreateStringValue(message));
234 web_ui_->CallJavascriptFunction("cr.quota.messageHandler_",
235 *message_data.get(),
236 value);
237 }
238
239 scoped_refptr<QuotaInternalsProxy> proxy_;
240
241 DISALLOW_COPY_AND_ASSIGN(QuotaInternalsMessageHandler);
242 };
243
244 typedef QuotaInternalsProxy QuotaInternalsProxyDeleter;
michaeln 2011/06/01 01:09:32 doesn't look used anywhere
tzik 2011/06/03 16:01:19 Done.
245
246 class QuotaInternalsProxy
247 : public base::RefCountedThreadSafe<QuotaInternalsProxy,
248 BrowserThread::DeleteOnIOThread> {
michaeln 2011/06/01 01:09:32 Extending the life of the QM shouldn't be an issue
tzik 2011/06/03 16:01:19 I see. Done.
249 public:
250 explicit QuotaInternalsProxy(QuotaInternalsMessageHandler* handler)
251 : handler_(handler),
252 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
253 }
254
255 // Called on IO Thread.
256 void ReportAvailableSpace(int64 available_space) {
257 BrowserThread::PostTask(
258 BrowserThread::UI, FROM_HERE,
259 NewRunnableMethod(
260 this, &QuotaInternalsProxy::RunReportAvailableSpaceOnUIThread,
261 available_space));
262 }
263
264 void ReportGlobalData(const GlobalData& data) {
265 BrowserThread::PostTask(
266 BrowserThread::UI, FROM_HERE,
267 NewRunnableMethod(
268 this, &QuotaInternalsProxy::RunReportGlobalDataOnUIThread,
269 data));
270 }
271
272 void ReportHostData(const std::vector<HostData>& hosts) {
273 BrowserThread::PostTask(
274 BrowserThread::UI, FROM_HERE,
275 NewRunnableMethod(
276 this, &QuotaInternalsProxy::RunReportHostDataOnUIThread,
277 hosts));
278 }
279
280 void ReportOriginData(const std::vector<OriginData>& origins) {
281 BrowserThread::PostTask(
282 BrowserThread::UI, FROM_HERE,
283 NewRunnableMethod(
284 this, &QuotaInternalsProxy::RunReportOriginDataOnUIThread,
285 origins));
286 }
287
288 void ReportStatistics(const Statistics& stats) {
289 BrowserThread::PostTask(
290 BrowserThread::UI, FROM_HERE,
291 NewRunnableMethod(
292 this, &QuotaInternalsProxy::RunReportStatisticsOnUIThread,
293 stats));
294 }
295
296 // Called on UI Thread.
297 void RequestData(quota::QuotaManager* quota_manager) {
298 BrowserThread::PostTask(
299 BrowserThread::IO, FROM_HERE,
300 NewRunnableMethod(this, &QuotaInternalsProxy::RunRequestDataOnIOThread,
301 make_scoped_refptr(quota_manager)));
302 }
303
304 private:
305 typedef quota::QuotaManager::QuotaTableEntry QuotaTableEntry;
306 typedef quota::QuotaManager::LastAccessTimeTableEntry
307 LastAccessTimeTableEntry;
308 typedef quota::QuotaManager::QuotaTableEntries QuotaTableEntries;
309 typedef quota::QuotaManager::LastAccessTimeTableEntries
310 LastAccessTimeTableEntries;
311
312 // Called on UI Thread.
313 void RunReportAvailableSpaceOnUIThread(int64 available_space) {
314 if (handler_)
315 handler_->ReportAvailableSpace(available_space);
316 }
317
318 void RunReportGlobalDataOnUIThread(const GlobalData& data) {
319 if (handler_)
320 handler_->ReportGlobalData(data);
321 }
322
323 void RunReportHostDataOnUIThread(const std::vector<HostData>& hosts) {
324 if (handler_)
325 handler_->ReportHostData(hosts);
326 }
327
328 void RunReportOriginDataOnUIThread(const std::vector<OriginData>& origins) {
329 if (handler_)
330 handler_->ReportOriginData(origins);
331 }
332
333 void RunReportStatisticsOnUIThread(const Statistics& stats) {
334 if (handler_)
335 handler_->ReportStatistics(stats);
336 }
337
338 // Called on IO Thread.
339 void RunRequestDataOnIOThread(
340 scoped_refptr<quota::QuotaManager> quota_manager) {
341 quota_manager_ = quota_manager->AsWeakPtr();
342
343 quota_manager->GetAvailableSpace(
344 callback_factory_.NewCallback(
345 &QuotaInternalsProxy::DidGetAvailableSpace));
346
347 quota_manager->GetTemporaryGlobalQuota(
348 callback_factory_.NewCallback(
349 &QuotaInternalsProxy::DidGetGlobalQuota));
350
351 quota_manager->GetGlobalUsage(
352 quota::kStorageTypeTemporary,
353 callback_factory_.NewCallback(
354 &QuotaInternalsProxy::DidGetGlobalUsage));
355
356 quota_manager->GetGlobalUsage(
357 quota::kStorageTypePersistent,
358 callback_factory_.NewCallback(
359 &QuotaInternalsProxy::DidGetGlobalUsage));
360
361 quota_manager->DumpQuotaTable(
362 callback_factory_.NewCallback(
363 &QuotaInternalsProxy::DidDumpQuotaTable));
364
365 quota_manager->DumpLastAccessTimeTable(
366 callback_factory_.NewCallback(
367 &QuotaInternalsProxy::DidDumpLastAccessTimeTable));
368
369 // TODO(tzik):
370 // Call QuotaManager::GetStatistics() (to be implemented.)
371 }
372
373 // Called on IO Thread by QuotaManager as callback.
374 void DidGetAvailableSpace(quota::QuotaStatusCode status, int64 space) {
375 if (status == quota::kQuotaStatusOk)
376 ReportAvailableSpace(space);
377 }
378
379 void DidGetGlobalQuota(quota::QuotaStatusCode status,
380 quota::StorageType type,
381 int64 quota) {
382 if (status == quota::kQuotaStatusOk)
383 ReportGlobalData(GlobalData(type, -1, -1, quota));
384 }
385
386 void DidGetGlobalUsage(quota::StorageType type,
387 int64 usage,
388 int64 unlimited_usage) {
389 ReportGlobalData(GlobalData(type, usage, unlimited_usage, -1));
390 RequestPerOriginData(type);
391 }
392
393 void DidDumpQuotaTable(const QuotaTableEntries& entries) {
394 std::vector<HostData> host_data;
395 host_data.reserve(entries.size());
396
397 typedef QuotaTableEntries::const_iterator iterator;
398 for (iterator itr(entries.begin()), end(entries.end());
399 itr != end; ++itr)
400 host_data.push_back(HostData(itr->host, itr->type, -1, itr->quota));
401 ReportHostData(host_data);
402 }
403
404 void DidDumpLastAccessTimeTable(const LastAccessTimeTableEntries& entries) {
405 std::vector<OriginData> origin_data;
406 origin_data.reserve(entries.size());
407
408 typedef LastAccessTimeTableEntries::const_iterator iterator;
409 for (iterator itr(entries.begin()), end(entries.end());
410 itr != end; ++itr)
411 origin_data.push_back(
412 OriginData(itr->origin, itr->type,
413 -1, itr->used_count, itr->last_access_time));
414 ReportOriginData(origin_data);
415 }
416
417 void DidGetHostUsage(const std::string& host,
418 quota::StorageType type,
419 int64 usage) {
420 DCHECK(type == quota::kStorageTypeTemporary ||
421 type == quota::kStorageTypePersistent);
422
423 report_pending_.push_back(
424 (HostData) {host, type, usage, -1});
michaeln 2011/06/01 01:09:32 use the ctor here instead
tzik 2011/06/03 16:01:19 Done.
425 hosts_pending_.erase(make_pair(host, type));
426 if (report_pending_.size() >= 10 || hosts_pending_.empty()) {
427 ReportHostData(report_pending_);
428 report_pending_.clear();
429 }
430
431 if (!hosts_pending_.empty())
432 GetHostUsage(hosts_pending_.begin()->first,
433 hosts_pending_.begin()->second);
434 }
435
436 // Helper. Called on IO Thread.
437 void RequestPerOriginData(quota::StorageType type);
438
439 void VisitHost(const std::string& host, quota::StorageType type) {
440 if (hosts_visited_.insert(std::make_pair(host, type)).second) {
441 hosts_pending_.insert(std::make_pair(host, type));
442 if (hosts_pending_.size() == 1) {
443 GetHostUsage(host, type);
444 }
445 }
446 }
447
448 void GetHostUsage(const std::string& host, quota::StorageType type) {
449 if (quota_manager_)
450 quota_manager_->GetHostUsage(
451 host, type,
452 callback_factory_.NewCallback(
453 &QuotaInternalsProxy::DidGetHostUsage));
454 }
455
456 // Used on UI Thread.
457 QuotaInternalsMessageHandler* handler_;
458
459 // Used on IO Thread.
460 base::ScopedCallbackFactory<QuotaInternalsProxy> callback_factory_;
461 base::WeakPtr<quota::QuotaManager> quota_manager_;
michaeln 2011/05/30 19:36:57 can this be a scoped_refptr<>
tzik 2011/06/03 16:01:19 Done.
462 std::set<std::pair<std::string, quota::StorageType> >
463 hosts_visited_, hosts_pending_;
464 std::vector<HostData> report_pending_;
465
466 friend class QuotaInternalsMessageHandler;
467 friend struct BrowserThread::DeleteOnThread<BrowserThread::IO>;
468 friend class DeleteTask<QuotaInternalsProxy>;
469
470 virtual ~QuotaInternalsProxy() {}
471 };
472
473 void QuotaInternalsMessageHandler::OnRequestData(const ListValue*) {
michaeln 2011/06/01 01:09:32 I'd move this method definition next to the other
tzik 2011/06/03 16:01:19 Done.
474 if (!proxy_)
475 proxy_ = new QuotaInternalsProxy(this);
476 proxy_->RequestData(web_ui_->GetProfile()->GetQuotaManager());
477 }
478
479 void QuotaInternalsProxy::RequestPerOriginData(quota::StorageType type) {
480 if (!quota_manager_)
481 return;
482
483 std::set<GURL> origins;
484 quota_manager_->GetCachedOrigins(type, &origins);
485
486 std::vector<OriginData> origin_data;
487 origin_data.reserve(origins.size());
488
489 std::set<std::string> hosts;
490 std::vector<HostData> host_data;
491
492 for (std::set<GURL>::iterator itr(origins.begin()), end(origins.end());
Evan Stade 2011/06/01 01:15:04 it's confusing to define a variable here that's no
tzik 2011/06/03 16:01:19 Done.
493 itr != end; ++itr) {
494 origin_data.push_back(
495 OriginData(*itr, type,
496 quota_manager_->IsOriginInUse(*itr) ? 1 : 0, -1,
497 base::Time()));
498
499 std::string host(net::GetHostOrSpecFromURL(*itr));
500 if (hosts.insert(host).second) {
501 host_data.push_back(HostData(host, type, -1, -1));
502 VisitHost(host, type);
503 }
504 }
505 ReportOriginData(origin_data);
506 ReportHostData(host_data);
507 }
508
509 QuotaInternalsMessageHandler::~QuotaInternalsMessageHandler() {
510 if (proxy_)
511 proxy_->handler_ = NULL;
512 }
513 } // namespace quota_internals
514
16 QuotaInternalsUI::QuotaInternalsUI(TabContents* contents) 515 QuotaInternalsUI::QuotaInternalsUI(TabContents* contents)
17 : WebUI(contents) { 516 : WebUI(contents) {
18 // TODO(tzik): implement and attach message handler 517 WebUIMessageHandler* handler =
518 new quota_internals::QuotaInternalsMessageHandler;
519 AddMessageHandler(handler->Attach(this));
19 contents->profile()->GetChromeURLDataManager()-> 520 contents->profile()->GetChromeURLDataManager()->
20 AddDataSource(new quota_internals::QuotaInternalsHTMLSource); 521 AddDataSource(new quota_internals::QuotaInternalsHTMLSource);
michaeln 2011/05/30 19:36:57 When is this data source removed? It looks like a
tzik 2011/05/31 04:53:01 Yes, we add DataSource in each quota-internals tab
michaeln 2011/06/01 01:09:32 I see, any old DataSource under this ones name is
21 } 522 }
22
23 namespace quota_internals {
24
25 QuotaInternalsHTMLSource::QuotaInternalsHTMLSource()
26 : DataSource(chrome::kChromeUIQuotaInternalsHost,
27 MessageLoop::current()) {
28 }
29
30 void QuotaInternalsHTMLSource::StartDataRequest(const std::string& path,
31 bool is_incognito,
32 int request_id) OVERRIDE {
33 base::StringPiece html(
34 ResourceBundle::GetSharedInstance().GetRawDataResource(
35 IDR_QUOTA_INTERNALS_INDEX_HTML));
36
37 scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
38 html_bytes->data.resize(html.size());
39 std::copy(html.data(), html.data() + html.size(), html_bytes->data.begin());
40 SendResponse(request_id, html_bytes);
41 return;
42 }
43
44 std::string QuotaInternalsHTMLSource::GetMimeType(
45 const std::string& path_unused) const {
46 return "text/html";
47 }
48
49 } // namespace quota_internals
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698