Add new certificateProvider extension API.
[chromium-blink-merge.git] / chrome / browser / ui / webui / about_ui.cc
blob11e32fa7527c366240a3d157626a7e52f2862ac3
1 // Copyright (c) 2012 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 "chrome/browser/ui/webui/about_ui.h"
7 #include <algorithm>
8 #include <string>
9 #include <utility>
10 #include <vector>
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "base/callback.h"
15 #include "base/command_line.h"
16 #include "base/files/file_util.h"
17 #include "base/format_macros.h"
18 #include "base/i18n/number_formatting.h"
19 #include "base/json/json_writer.h"
20 #include "base/memory/singleton.h"
21 #include "base/metrics/statistics_recorder.h"
22 #include "base/strings/string_number_conversions.h"
23 #include "base/strings/string_piece.h"
24 #include "base/strings/string_split.h"
25 #include "base/strings/string_util.h"
26 #include "base/strings/stringprintf.h"
27 #include "base/strings/utf_string_conversions.h"
28 #include "base/threading/thread.h"
29 #include "base/values.h"
30 #include "chrome/browser/about_flags.h"
31 #include "chrome/browser/browser_process.h"
32 #include "chrome/browser/defaults.h"
33 #include "chrome/browser/memory/oom_priority_manager.h"
34 #include "chrome/browser/memory/tab_stats.h"
35 #include "chrome/browser/memory_details.h"
36 #include "chrome/browser/net/predictor.h"
37 #include "chrome/browser/profiles/profile.h"
38 #include "chrome/browser/profiles/profile_manager.h"
39 #include "chrome/browser/ui/browser_dialogs.h"
40 #include "chrome/common/chrome_paths.h"
41 #include "chrome/common/url_constants.h"
42 #include "chrome/grit/chromium_strings.h"
43 #include "chrome/grit/generated_resources.h"
44 #include "chrome/grit/locale_settings.h"
45 #include "content/public/browser/browser_thread.h"
46 #include "content/public/browser/render_process_host.h"
47 #include "content/public/browser/render_view_host.h"
48 #include "content/public/browser/url_data_source.h"
49 #include "content/public/browser/web_contents.h"
50 #include "content/public/common/content_client.h"
51 #include "content/public/common/process_type.h"
52 #include "google_apis/gaia/google_service_auth_error.h"
53 #include "grit/browser_resources.h"
54 #include "net/base/escape.h"
55 #include "net/base/filename_util.h"
56 #include "net/base/load_flags.h"
57 #include "net/http/http_response_headers.h"
58 #include "net/url_request/url_fetcher.h"
59 #include "net/url_request/url_request_status.h"
60 #include "ui/base/l10n/l10n_util.h"
61 #include "ui/base/resource/resource_bundle.h"
62 #include "ui/base/webui/jstemplate_builder.h"
63 #include "ui/base/webui/web_ui_util.h"
64 #include "url/gurl.h"
66 #if defined(ENABLE_THEMES)
67 #include "chrome/browser/ui/webui/theme_source.h"
68 #endif
70 #if defined(OS_LINUX) || defined(OS_OPENBSD)
71 #include "content/public/browser/zygote_host_linux.h"
72 #include "content/public/common/sandbox_linux.h"
73 #endif
75 #if defined(OS_WIN)
76 #include "chrome/browser/enumerate_modules_model_win.h"
77 #endif
79 #if defined(OS_CHROMEOS)
80 #include "chrome/browser/browser_process_platform_part_chromeos.h"
81 #include "chrome/browser/chromeos/customization/customization_document.h"
82 #endif
84 using base::Time;
85 using base::TimeDelta;
86 using content::BrowserThread;
87 using content::WebContents;
89 namespace {
91 const char kCreditsJsPath[] = "credits.js";
92 const char kMemoryJsPath[] = "memory.js";
93 const char kMemoryCssPath[] = "about_memory.css";
94 const char kStatsJsPath[] = "stats.js";
95 const char kStringsJsPath[] = "strings.js";
97 // When you type about:memory, it actually loads this intermediate URL that
98 // redirects you to the final page. This avoids the problem where typing
99 // "about:memory" on the new tab page or any other page where a process
100 // transition would occur to the about URL will cause some confusion.
102 // The problem is that during the processing of the memory page, there are two
103 // processes active, the original and the destination one. This can create the
104 // impression that we're using more resources than we actually are. This
105 // redirect solves the problem by eliminating the process transition during the
106 // time that about memory is being computed.
107 std::string GetAboutMemoryRedirectResponse(Profile* profile) {
108 return base::StringPrintf("<meta http-equiv='refresh' content='0;%s'>",
109 chrome::kChromeUIMemoryRedirectURL);
112 // Handling about:memory is complicated enough to encapsulate its related
113 // methods into a single class. The user should create it (on the heap) and call
114 // its |StartFetch()| method.
115 class AboutMemoryHandler : public MemoryDetails {
116 public:
117 explicit AboutMemoryHandler(
118 const content::URLDataSource::GotDataCallback& callback)
119 : callback_(callback) {
122 void OnDetailsAvailable() override;
124 private:
125 ~AboutMemoryHandler() override {}
127 void BindProcessMetrics(base::DictionaryValue* data,
128 ProcessMemoryInformation* info);
129 void AppendProcess(base::ListValue* child_data,
130 ProcessMemoryInformation* info);
132 content::URLDataSource::GotDataCallback callback_;
134 DISALLOW_COPY_AND_ASSIGN(AboutMemoryHandler);
137 #if defined(OS_CHROMEOS)
139 const char kKeyboardUtilsPath[] = "keyboard_utils.js";
141 // chrome://terms falls back to offline page after kOnlineTermsTimeoutSec.
142 const int kOnlineTermsTimeoutSec = 7;
144 // Helper class that fetches the online Chrome OS terms. Empty string is
145 // returned once fetching failed or exceeded |kOnlineTermsTimeoutSec|.
146 class ChromeOSOnlineTermsHandler : public net::URLFetcherDelegate {
147 public:
148 typedef base::Callback<void (ChromeOSOnlineTermsHandler*)> FetchCallback;
150 explicit ChromeOSOnlineTermsHandler(const FetchCallback& callback,
151 const std::string& locale)
152 : fetch_callback_(callback) {
153 std::string eula_URL = base::StringPrintf(chrome::kOnlineEulaURLPath,
154 locale.c_str());
155 eula_fetcher_ =
156 net::URLFetcher::Create(0 /* ID used for testing */, GURL(eula_URL),
157 net::URLFetcher::GET, this);
158 eula_fetcher_->SetRequestContext(
159 g_browser_process->system_request_context());
160 eula_fetcher_->AddExtraRequestHeader("Accept: text/html");
161 eula_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
162 net::LOAD_DO_NOT_SAVE_COOKIES |
163 net::LOAD_DISABLE_CACHE);
164 eula_fetcher_->Start();
165 // Abort the download attempt if it takes longer than one minute.
166 download_timer_.Start(FROM_HERE,
167 base::TimeDelta::FromSeconds(kOnlineTermsTimeoutSec),
168 this,
169 &ChromeOSOnlineTermsHandler::OnDownloadTimeout);
172 void GetResponseResult(std::string* response_string) {
173 std::string mime_type;
174 if (!eula_fetcher_ ||
175 !eula_fetcher_->GetStatus().is_success() ||
176 eula_fetcher_->GetResponseCode() != 200 ||
177 !eula_fetcher_->GetResponseHeaders()->GetMimeType(&mime_type) ||
178 mime_type != "text/html" ||
179 !eula_fetcher_->GetResponseAsString(response_string)) {
180 response_string->clear();
184 private:
185 // Prevents allocation on the stack. ChromeOSOnlineTermsHandler should be
186 // created by 'operator new'. |this| takes care of destruction.
187 ~ChromeOSOnlineTermsHandler() override {}
189 // net::URLFetcherDelegate:
190 void OnURLFetchComplete(const net::URLFetcher* source) override {
191 if (source != eula_fetcher_.get()) {
192 NOTREACHED() << "Callback from foreign URL fetcher";
193 return;
195 fetch_callback_.Run(this);
196 delete this;
199 void OnDownloadTimeout() {
200 eula_fetcher_.reset();
201 fetch_callback_.Run(this);
202 delete this;
205 // Timer that enforces a timeout on the attempt to download the
206 // ChromeOS Terms.
207 base::OneShotTimer<ChromeOSOnlineTermsHandler> download_timer_;
209 // |fetch_callback_| called when fetching succeeded or failed.
210 FetchCallback fetch_callback_;
212 // Helper to fetch online eula.
213 scoped_ptr<net::URLFetcher> eula_fetcher_;
215 DISALLOW_COPY_AND_ASSIGN(ChromeOSOnlineTermsHandler);
218 class ChromeOSTermsHandler
219 : public base::RefCountedThreadSafe<ChromeOSTermsHandler> {
220 public:
221 static void Start(const std::string& path,
222 const content::URLDataSource::GotDataCallback& callback) {
223 scoped_refptr<ChromeOSTermsHandler> handler(
224 new ChromeOSTermsHandler(path, callback));
225 handler->StartOnUIThread();
228 private:
229 friend class base::RefCountedThreadSafe<ChromeOSTermsHandler>;
231 ChromeOSTermsHandler(const std::string& path,
232 const content::URLDataSource::GotDataCallback& callback)
233 : path_(path),
234 callback_(callback),
235 // Previously we were using "initial locale" http://crbug.com/145142
236 locale_(g_browser_process->GetApplicationLocale()) {
239 virtual ~ChromeOSTermsHandler() {}
241 void StartOnUIThread() {
242 DCHECK_CURRENTLY_ON(BrowserThread::UI);
243 if (path_ == chrome::kOemEulaURLPath) {
244 // Load local OEM EULA from the disk.
245 BrowserThread::PostTask(
246 BrowserThread::FILE, FROM_HERE,
247 base::Bind(&ChromeOSTermsHandler::LoadOemEulaFileOnFileThread, this));
248 } else {
249 // Try to load online version of ChromeOS terms first.
250 // ChromeOSOnlineTermsHandler object destroys itself.
251 new ChromeOSOnlineTermsHandler(
252 base::Bind(&ChromeOSTermsHandler::OnOnlineEULAFetched, this),
253 locale_);
257 void OnOnlineEULAFetched(ChromeOSOnlineTermsHandler* loader) {
258 DCHECK_CURRENTLY_ON(BrowserThread::UI);
259 loader->GetResponseResult(&contents_);
260 if (contents_.empty()) {
261 // Load local ChromeOS terms from the file.
262 BrowserThread::PostTask(
263 BrowserThread::FILE, FROM_HERE,
264 base::Bind(&ChromeOSTermsHandler::LoadEulaFileOnFileThread, this));
265 } else {
266 ResponseOnUIThread();
270 void LoadOemEulaFileOnFileThread() {
271 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
272 const chromeos::StartupCustomizationDocument* customization =
273 chromeos::StartupCustomizationDocument::GetInstance();
274 if (customization->IsReady()) {
275 base::FilePath oem_eula_file_path;
276 if (net::FileURLToFilePath(GURL(customization->GetEULAPage(locale_)),
277 &oem_eula_file_path)) {
278 if (!base::ReadFileToString(oem_eula_file_path, &contents_)) {
279 contents_.clear();
283 BrowserThread::PostTask(
284 BrowserThread::UI, FROM_HERE,
285 base::Bind(&ChromeOSTermsHandler::ResponseOnUIThread, this));
288 void LoadEulaFileOnFileThread() {
289 std::string file_path =
290 base::StringPrintf(chrome::kEULAPathFormat, locale_.c_str());
291 if (!base::ReadFileToString(base::FilePath(file_path), &contents_)) {
292 // No EULA for given language - try en-US as default.
293 file_path = base::StringPrintf(chrome::kEULAPathFormat, "en-US");
294 if (!base::ReadFileToString(base::FilePath(file_path), &contents_)) {
295 // File with EULA not found, ResponseOnUIThread will load EULA from
296 // resources if contents_ is empty.
297 contents_.clear();
300 BrowserThread::PostTask(
301 BrowserThread::UI, FROM_HERE,
302 base::Bind(&ChromeOSTermsHandler::ResponseOnUIThread, this));
305 void ResponseOnUIThread() {
306 DCHECK_CURRENTLY_ON(BrowserThread::UI);
307 // If we fail to load Chrome OS EULA from disk, load it from resources.
308 // Do nothing if OEM EULA load failed.
309 if (contents_.empty() && path_ != chrome::kOemEulaURLPath)
310 contents_ = l10n_util::GetStringUTF8(IDS_TERMS_HTML);
311 callback_.Run(base::RefCountedString::TakeString(&contents_));
314 // Path in the URL.
315 const std::string path_;
317 // Callback to run with the response.
318 content::URLDataSource::GotDataCallback callback_;
320 // Locale of the EULA.
321 const std::string locale_;
323 // EULA contents that was loaded from file.
324 std::string contents_;
326 DISALLOW_COPY_AND_ASSIGN(ChromeOSTermsHandler);
329 class ChromeOSCreditsHandler
330 : public base::RefCountedThreadSafe<ChromeOSCreditsHandler> {
331 public:
332 static void Start(const std::string& path,
333 const content::URLDataSource::GotDataCallback& callback) {
334 scoped_refptr<ChromeOSCreditsHandler> handler(
335 new ChromeOSCreditsHandler(path, callback));
336 handler->StartOnUIThread();
339 private:
340 friend class base::RefCountedThreadSafe<ChromeOSCreditsHandler>;
342 ChromeOSCreditsHandler(
343 const std::string& path,
344 const content::URLDataSource::GotDataCallback& callback)
345 : path_(path), callback_(callback) {}
347 virtual ~ChromeOSCreditsHandler() {}
349 void StartOnUIThread() {
350 DCHECK_CURRENTLY_ON(BrowserThread::UI);
351 if (path_ == kKeyboardUtilsPath) {
352 contents_ = ResourceBundle::GetSharedInstance()
353 .GetRawDataResource(IDR_KEYBOARD_UTILS_JS)
354 .as_string();
355 ResponseOnUIThread();
356 return;
358 // Load local Chrome OS credits from the disk.
359 BrowserThread::PostBlockingPoolTaskAndReply(
360 FROM_HERE,
361 base::Bind(&ChromeOSCreditsHandler::LoadCreditsFileOnBlockingPool,
362 this),
363 base::Bind(&ChromeOSCreditsHandler::ResponseOnUIThread, this));
366 void LoadCreditsFileOnBlockingPool() {
367 DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
368 base::FilePath credits_file_path(chrome::kChromeOSCreditsPath);
369 if (!base::ReadFileToString(credits_file_path, &contents_)) {
370 // File with credits not found, ResponseOnUIThread will load credits
371 // from resources if contents_ is empty.
372 contents_.clear();
376 void ResponseOnUIThread() {
377 DCHECK_CURRENTLY_ON(BrowserThread::UI);
378 // If we fail to load Chrome OS credits from disk, load it from resources.
379 if (contents_.empty() && path_ != kKeyboardUtilsPath) {
380 contents_ = ResourceBundle::GetSharedInstance()
381 .GetRawDataResource(IDR_OS_CREDITS_HTML)
382 .as_string();
384 callback_.Run(base::RefCountedString::TakeString(&contents_));
387 // Path in the URL.
388 const std::string path_;
390 // Callback to run with the response.
391 content::URLDataSource::GotDataCallback callback_;
393 // Chrome OS credits contents that was loaded from file.
394 std::string contents_;
396 DISALLOW_COPY_AND_ASSIGN(ChromeOSCreditsHandler);
398 #endif
400 } // namespace
402 // Individual about handlers ---------------------------------------------------
404 namespace about_ui {
406 void AppendHeader(std::string* output, int refresh,
407 const std::string& unescaped_title) {
408 output->append("<!DOCTYPE HTML>\n<html>\n<head>\n");
409 if (!unescaped_title.empty()) {
410 output->append("<title>");
411 output->append(net::EscapeForHTML(unescaped_title));
412 output->append("</title>\n");
414 output->append("<meta charset='utf-8'>\n");
415 if (refresh > 0) {
416 output->append("<meta http-equiv='refresh' content='");
417 output->append(base::IntToString(refresh));
418 output->append("'/>\n");
422 void AppendBody(std::string *output) {
423 output->append("</head>\n<body>\n");
426 void AppendFooter(std::string *output) {
427 output->append("</body>\n</html>\n");
430 } // namespace about_ui
432 using about_ui::AppendHeader;
433 using about_ui::AppendBody;
434 using about_ui::AppendFooter;
436 namespace {
438 std::string ChromeURLs() {
439 std::string html;
440 AppendHeader(&html, 0, "Chrome URLs");
441 AppendBody(&html);
442 html += "<h2>List of Chrome URLs</h2>\n<ul>\n";
443 std::vector<std::string> hosts(
444 chrome::kChromeHostURLs,
445 chrome::kChromeHostURLs + chrome::kNumberOfChromeHostURLs);
446 std::sort(hosts.begin(), hosts.end());
447 for (std::vector<std::string>::const_iterator i = hosts.begin();
448 i != hosts.end(); ++i)
449 html += "<li><a href='chrome://" + *i + "/'>chrome://" + *i + "</a></li>\n";
450 html += "</ul>\n<h2>For Debug</h2>\n"
451 "<p>The following pages are for debugging purposes only. Because they "
452 "crash or hang the renderer, they're not linked directly; you can type "
453 "them into the address bar if you need them.</p>\n<ul>";
454 for (int i = 0; i < chrome::kNumberOfChromeDebugURLs; i++)
455 html += "<li>" + std::string(chrome::kChromeDebugURLs[i]) + "</li>\n";
456 html += "</ul>\n";
457 AppendFooter(&html);
458 return html;
461 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
463 const char kAboutDiscardsRunCommand[] = "run";
465 // Html output helper functions
467 // Helper function to wrap HTML with a tag.
468 std::string WrapWithTag(const std::string& tag, const std::string& text) {
469 return "<" + tag + ">" + text + "</" + tag + ">";
472 // Helper function to wrap Html with <td> tag.
473 std::string WrapWithTD(const std::string& text) {
474 return "<td>" + text + "</td>";
477 // Helper function to wrap Html with <tr> tag.
478 std::string WrapWithTR(const std::string& text) {
479 return "<tr>" + text + "</tr>";
482 std::string AddStringRow(const std::string& name, const std::string& value) {
483 std::string row;
484 row.append(WrapWithTD(name));
485 row.append(WrapWithTD(value));
486 return WrapWithTR(row);
489 void AddContentSecurityPolicy(std::string* output) {
490 output->append("<meta http-equiv='Content-Security-Policy' "
491 "content='default-src 'none';'>");
494 // TODO(stevenjb): L10N AboutDiscards.
496 std::string BuildAboutDiscardsRunPage() {
497 std::string output;
498 AppendHeader(&output, 0, "About discards");
499 output.append(base::StringPrintf("<meta http-equiv='refresh' content='2;%s'>",
500 chrome::kChromeUIDiscardsURL));
501 AddContentSecurityPolicy(&output);
502 output.append(WrapWithTag("p", "Discarding a tab..."));
503 AppendFooter(&output);
504 return output;
507 std::vector<std::string> GetHtmlTabDescriptorsForDiscardPage() {
508 memory::OomPriorityManager* oom = g_browser_process->GetOomPriorityManager();
509 memory::TabStatsList stats = oom->GetTabStats();
510 std::vector<std::string> titles;
511 titles.reserve(stats.size());
512 for (memory::TabStatsList::iterator it = stats.begin(); it != stats.end();
513 ++it) {
514 std::string str;
515 str.reserve(4096);
516 str += "<b>";
517 str += it->is_app ? "[App] " : "";
518 str += it->is_internal_page ? "[Internal] " : "";
519 str += it->is_playing_audio ? "[Audio] " : "";
520 str += it->is_pinned ? "[Pinned] " : "";
521 str += it->is_discarded ? "[Discarded] " : "";
522 str += "</b>";
523 str += net::EscapeForHTML(base::UTF16ToUTF8(it->title));
524 #if defined(OS_CHROMEOS)
525 str += base::StringPrintf(" (%d) ", it->oom_score);
526 #endif
527 if (!it->is_discarded) {
528 str += base::StringPrintf(" <a href='%s%s/%" PRId64 "'>Discard</a>",
529 chrome::kChromeUIDiscardsURL,
530 kAboutDiscardsRunCommand, it->tab_contents_id);
532 titles.push_back(str);
534 return titles;
537 std::string AboutDiscards(const std::string& path) {
538 std::string output;
539 int64 web_content_id;
540 memory::OomPriorityManager* oom = g_browser_process->GetOomPriorityManager();
542 std::vector<std::string> path_split = base::SplitString(
543 path, "/", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
544 if (path_split.size() == 2 && path_split[0] == kAboutDiscardsRunCommand &&
545 base::StringToInt64(path_split[1], &web_content_id)) {
546 oom->DiscardTabById(web_content_id);
547 return BuildAboutDiscardsRunPage();
548 } else if (path_split.size() == 1 &&
549 path_split[0] == kAboutDiscardsRunCommand) {
550 oom->DiscardTab();
551 return BuildAboutDiscardsRunPage();
554 AppendHeader(&output, 0, "About discards");
555 AddContentSecurityPolicy(&output);
556 AppendBody(&output);
557 output.append("<h3>Discarded Tabs</h3>");
558 output.append(
559 "<p>Tabs sorted from most interesting to least interesting. The least "
560 "interesting tab may be discarded if we run out of physical memory.</p>");
562 std::vector<std::string> titles = GetHtmlTabDescriptorsForDiscardPage();
563 if (!titles.empty()) {
564 output.append("<ul>");
565 std::vector<std::string>::iterator it = titles.begin();
566 for ( ; it != titles.end(); ++it) {
567 output.append(WrapWithTag("li", *it));
569 output.append("</ul>");
570 } else {
571 output.append("<p>None found. Wait 10 seconds, then refresh.</p>");
573 output.append(
574 base::StringPrintf("%d discards this session. ", oom->discard_count()));
575 output.append(base::StringPrintf("<a href='%s%s'>Discard tab now</a>",
576 chrome::kChromeUIDiscardsURL,
577 kAboutDiscardsRunCommand));
579 base::SystemMemoryInfoKB meminfo;
580 base::GetSystemMemoryInfo(&meminfo);
581 output.append("<h3>System memory information in MB</h3>");
582 output.append("<table>");
583 // Start with summary statistics.
584 output.append(AddStringRow(
585 "Total", base::IntToString(meminfo.total / 1024)));
586 output.append(AddStringRow(
587 "Free", base::IntToString(meminfo.free / 1024)));
588 #if defined(OS_CHROMEOS)
589 int mem_allocated_kb = meminfo.active_anon + meminfo.inactive_anon;
590 #if defined(ARCH_CPU_ARM_FAMILY)
591 // ARM counts allocated graphics memory separately from anonymous.
592 if (meminfo.gem_size != -1)
593 mem_allocated_kb += meminfo.gem_size / 1024;
594 #endif
595 output.append(AddStringRow(
596 "Allocated", base::IntToString(mem_allocated_kb / 1024)));
597 // Add some space, then detailed numbers.
598 output.append(AddStringRow("&nbsp;", "&nbsp;"));
599 output.append(AddStringRow(
600 "Buffered", base::IntToString(meminfo.buffers / 1024)));
601 output.append(AddStringRow(
602 "Cached", base::IntToString(meminfo.cached / 1024)));
603 output.append(AddStringRow(
604 "Active Anon", base::IntToString(meminfo.active_anon / 1024)));
605 output.append(AddStringRow(
606 "Inactive Anon", base::IntToString(meminfo.inactive_anon / 1024)));
607 output.append(AddStringRow(
608 "Shared", base::IntToString(meminfo.shmem / 1024)));
609 output.append(AddStringRow(
610 "Graphics", base::IntToString(meminfo.gem_size / 1024 / 1024)));
611 #endif // OS_CHROMEOS
612 output.append("</table>");
613 AppendFooter(&output);
614 return output;
617 #endif // OS_WIN || OS_CHROMEOS
619 // AboutDnsHandler bounces the request back to the IO thread to collect
620 // the DNS information.
621 class AboutDnsHandler : public base::RefCountedThreadSafe<AboutDnsHandler> {
622 public:
623 static void Start(Profile* profile,
624 const content::URLDataSource::GotDataCallback& callback) {
625 scoped_refptr<AboutDnsHandler> handler(
626 new AboutDnsHandler(profile, callback));
627 handler->StartOnUIThread();
630 private:
631 friend class base::RefCountedThreadSafe<AboutDnsHandler>;
633 AboutDnsHandler(Profile* profile,
634 const content::URLDataSource::GotDataCallback& callback)
635 : profile_(profile),
636 callback_(callback) {
637 DCHECK_CURRENTLY_ON(BrowserThread::UI);
640 virtual ~AboutDnsHandler() {}
642 // Calls FinishOnUIThread() on completion.
643 void StartOnUIThread() {
644 DCHECK_CURRENTLY_ON(BrowserThread::UI);
645 chrome_browser_net::Predictor* predictor = profile_->GetNetworkPredictor();
646 BrowserThread::PostTask(
647 BrowserThread::IO, FROM_HERE,
648 base::Bind(&AboutDnsHandler::StartOnIOThread, this, predictor));
651 void StartOnIOThread(chrome_browser_net::Predictor* predictor) {
652 DCHECK_CURRENTLY_ON(BrowserThread::IO);
654 std::string data;
655 AppendHeader(&data, 0, "About DNS");
656 AppendBody(&data);
657 chrome_browser_net::Predictor::PredictorGetHtmlInfo(predictor, &data);
658 AppendFooter(&data);
660 BrowserThread::PostTask(
661 BrowserThread::UI, FROM_HERE,
662 base::Bind(&AboutDnsHandler::FinishOnUIThread, this, data));
665 void FinishOnUIThread(const std::string& data) {
666 DCHECK_CURRENTLY_ON(BrowserThread::UI);
667 std::string data_copy(data);
668 callback_.Run(base::RefCountedString::TakeString(&data_copy));
671 Profile* profile_;
673 // Callback to run with the response.
674 content::URLDataSource::GotDataCallback callback_;
676 DISALLOW_COPY_AND_ASSIGN(AboutDnsHandler);
679 void FinishMemoryDataRequest(
680 const std::string& path,
681 const content::URLDataSource::GotDataCallback& callback) {
682 if (path == kStringsJsPath) {
683 // The AboutMemoryHandler cleans itself up, but |StartFetch()| will want
684 // the refcount to be greater than 0.
685 scoped_refptr<AboutMemoryHandler> handler(new AboutMemoryHandler(callback));
686 handler->StartFetch(MemoryDetails::FROM_ALL_BROWSERS);
687 } else {
688 int id = IDR_ABOUT_MEMORY_HTML;
689 if (path == kMemoryJsPath) {
690 id = IDR_ABOUT_MEMORY_JS;
691 } else if (path == kMemoryCssPath) {
692 id = IDR_ABOUT_MEMORY_CSS;
695 std::string result =
696 ResourceBundle::GetSharedInstance().GetRawDataResource(id).as_string();
697 callback.Run(base::RefCountedString::TakeString(&result));
701 #if defined(OS_LINUX) || defined(OS_OPENBSD)
702 std::string AboutLinuxProxyConfig() {
703 std::string data;
704 AppendHeader(&data, 0,
705 l10n_util::GetStringUTF8(IDS_ABOUT_LINUX_PROXY_CONFIG_TITLE));
706 data.append("<style>body { max-width: 70ex; padding: 2ex 5ex; }</style>");
707 AppendBody(&data);
708 base::FilePath binary = base::CommandLine::ForCurrentProcess()->GetProgram();
709 data.append(l10n_util::GetStringFUTF8(
710 IDS_ABOUT_LINUX_PROXY_CONFIG_BODY,
711 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
712 base::ASCIIToUTF16(binary.BaseName().value())));
713 AppendFooter(&data);
714 return data;
717 void AboutSandboxRow(std::string* data, int name_id, bool good) {
718 data->append("<tr><td>");
719 data->append(l10n_util::GetStringUTF8(name_id));
720 if (good) {
721 data->append("</td><td style='color: green;'>");
722 data->append(
723 l10n_util::GetStringUTF8(IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL));
724 } else {
725 data->append("</td><td style='color: red;'>");
726 data->append(
727 l10n_util::GetStringUTF8(IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL));
729 data->append("</td></tr>");
732 std::string AboutSandbox() {
733 std::string data;
734 AppendHeader(&data, 0, l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_TITLE));
735 AppendBody(&data);
736 data.append("<h1>");
737 data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_TITLE));
738 data.append("</h1>");
740 // Get expected sandboxing status of renderers.
741 const int status = content::ZygoteHost::GetInstance()->GetSandboxStatus();
743 data.append("<table>");
745 AboutSandboxRow(&data, IDS_ABOUT_SANDBOX_SUID_SANDBOX,
746 status & content::kSandboxLinuxSUID);
747 AboutSandboxRow(&data, IDS_ABOUT_SANDBOX_NAMESPACE_SANDBOX,
748 status & content::kSandboxLinuxUserNS);
749 AboutSandboxRow(&data, IDS_ABOUT_SANDBOX_PID_NAMESPACES,
750 status & content::kSandboxLinuxPIDNS);
751 AboutSandboxRow(&data, IDS_ABOUT_SANDBOX_NET_NAMESPACES,
752 status & content::kSandboxLinuxNetNS);
753 AboutSandboxRow(&data, IDS_ABOUT_SANDBOX_SECCOMP_BPF_SANDBOX,
754 status & content::kSandboxLinuxSeccompBPF);
755 AboutSandboxRow(&data, IDS_ABOUT_SANDBOX_SECCOMP_BPF_SANDBOX_TSYNC,
756 status & content::kSandboxLinuxSeccompTSYNC);
757 AboutSandboxRow(&data, IDS_ABOUT_SANDBOX_YAMA_LSM,
758 status & content::kSandboxLinuxYama);
760 data.append("</table>");
762 // Require either the setuid or namespace sandbox for our first-layer sandbox.
763 bool good_layer1 = (status & content::kSandboxLinuxSUID ||
764 status & content::kSandboxLinuxUserNS) &&
765 status & content::kSandboxLinuxPIDNS &&
766 status & content::kSandboxLinuxNetNS;
767 // A second-layer sandbox is also required to be adequately sandboxed.
768 bool good_layer2 = status & content::kSandboxLinuxSeccompBPF;
769 bool good = good_layer1 && good_layer2;
771 if (good) {
772 data.append("<p style='color: green'>");
773 data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_OK));
774 } else {
775 data.append("<p style='color: red'>");
776 data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_BAD));
778 data.append("</p>");
780 AppendFooter(&data);
781 return data;
783 #endif
785 // AboutMemoryHandler ----------------------------------------------------------
787 // Helper for AboutMemory to bind results from a ProcessMetrics object
788 // to a DictionaryValue. Fills ws_usage and comm_usage so that the objects
789 // can be used in caller's scope (e.g for appending to a net total).
790 void AboutMemoryHandler::BindProcessMetrics(base::DictionaryValue* data,
791 ProcessMemoryInformation* info) {
792 DCHECK(data && info);
794 // Bind metrics to dictionary.
795 data->SetInteger("ws_priv", static_cast<int>(info->working_set.priv));
796 data->SetInteger("ws_shareable",
797 static_cast<int>(info->working_set.shareable));
798 data->SetInteger("ws_shared", static_cast<int>(info->working_set.shared));
799 data->SetInteger("comm_priv", static_cast<int>(info->committed.priv));
800 data->SetInteger("comm_map", static_cast<int>(info->committed.mapped));
801 data->SetInteger("comm_image", static_cast<int>(info->committed.image));
802 data->SetInteger("pid", info->pid);
803 data->SetString("version", info->version);
804 data->SetInteger("processes", info->num_processes);
807 // Helper for AboutMemory to append memory usage information for all
808 // sub-processes (i.e. renderers, plugins) used by Chrome.
809 void AboutMemoryHandler::AppendProcess(base::ListValue* child_data,
810 ProcessMemoryInformation* info) {
811 DCHECK(child_data && info);
813 // Append a new DictionaryValue for this renderer to our list.
814 base::DictionaryValue* child = new base::DictionaryValue();
815 child_data->Append(child);
816 BindProcessMetrics(child, info);
818 std::string child_label(
819 ProcessMemoryInformation::GetFullTypeNameInEnglish(info->process_type,
820 info->renderer_type));
821 if (info->is_diagnostics)
822 child_label.append(" (diagnostics)");
823 child->SetString("child_name", child_label);
824 base::ListValue* titles = new base::ListValue();
825 child->Set("titles", titles);
826 for (size_t i = 0; i < info->titles.size(); ++i)
827 titles->Append(new base::StringValue(info->titles[i]));
830 void AboutMemoryHandler::OnDetailsAvailable() {
831 // the root of the JSON hierarchy for about:memory jstemplate
832 scoped_ptr<base::DictionaryValue> root(new base::DictionaryValue);
833 base::ListValue* browsers = new base::ListValue();
834 root->Set("browsers", browsers);
836 const std::vector<ProcessData>& browser_processes = processes();
838 // Aggregate per-process data into browser summary data.
839 base::string16 log_string;
840 for (size_t index = 0; index < browser_processes.size(); index++) {
841 if (browser_processes[index].processes.empty())
842 continue;
844 // Sum the information for the processes within this browser.
845 ProcessMemoryInformation aggregate;
846 ProcessMemoryInformationList::const_iterator iterator;
847 iterator = browser_processes[index].processes.begin();
848 aggregate.pid = iterator->pid;
849 aggregate.version = iterator->version;
850 while (iterator != browser_processes[index].processes.end()) {
851 if (!iterator->is_diagnostics ||
852 browser_processes[index].processes.size() == 1) {
853 aggregate.working_set.priv += iterator->working_set.priv;
854 aggregate.working_set.shared += iterator->working_set.shared;
855 aggregate.working_set.shareable += iterator->working_set.shareable;
856 aggregate.committed.priv += iterator->committed.priv;
857 aggregate.committed.mapped += iterator->committed.mapped;
858 aggregate.committed.image += iterator->committed.image;
859 aggregate.num_processes++;
861 ++iterator;
863 base::DictionaryValue* browser_data = new base::DictionaryValue();
864 browsers->Append(browser_data);
865 browser_data->SetString("name", browser_processes[index].name);
867 BindProcessMetrics(browser_data, &aggregate);
869 // We log memory info as we record it.
870 if (!log_string.empty())
871 log_string += base::ASCIIToUTF16(", ");
872 log_string += browser_processes[index].name + base::ASCIIToUTF16(", ") +
873 base::Int64ToString16(aggregate.working_set.priv) +
874 base::ASCIIToUTF16(", ") +
875 base::Int64ToString16(aggregate.working_set.shared) +
876 base::ASCIIToUTF16(", ") +
877 base::Int64ToString16(aggregate.working_set.shareable);
879 if (!log_string.empty())
880 VLOG(1) << "memory: " << log_string;
882 // Set the browser & renderer detailed process data.
883 base::DictionaryValue* browser_data = new base::DictionaryValue();
884 root->Set("browzr_data", browser_data);
885 base::ListValue* child_data = new base::ListValue();
886 root->Set("child_data", child_data);
888 ProcessData process = browser_processes[0]; // Chrome is the first browser.
889 root->SetString("current_browser_name", process.name);
891 for (size_t index = 0; index < process.processes.size(); index++) {
892 if (process.processes[index].process_type == content::PROCESS_TYPE_BROWSER)
893 BindProcessMetrics(browser_data, &process.processes[index]);
894 else
895 AppendProcess(child_data, &process.processes[index]);
898 root->SetBoolean("show_other_browsers",
899 browser_defaults::kShowOtherBrowsersInAboutMemory);
901 base::DictionaryValue load_time_data;
902 load_time_data.SetString(
903 "summary_desc",
904 l10n_util::GetStringUTF16(IDS_MEMORY_USAGE_SUMMARY_DESC));
905 const std::string& app_locale = g_browser_process->GetApplicationLocale();
906 webui::SetLoadTimeDataDefaults(app_locale, &load_time_data);
907 load_time_data.Set("jstemplateData", root.release());
909 std::string data;
910 webui::AppendJsonJS(&load_time_data, &data);
911 callback_.Run(base::RefCountedString::TakeString(&data));
914 } // namespace
916 // AboutUIHTMLSource ----------------------------------------------------------
918 AboutUIHTMLSource::AboutUIHTMLSource(const std::string& source_name,
919 Profile* profile)
920 : source_name_(source_name),
921 profile_(profile) {}
923 AboutUIHTMLSource::~AboutUIHTMLSource() {}
925 std::string AboutUIHTMLSource::GetSource() const {
926 return source_name_;
929 void AboutUIHTMLSource::StartDataRequest(
930 const std::string& path,
931 int render_process_id,
932 int render_frame_id,
933 const content::URLDataSource::GotDataCallback& callback) {
934 std::string response;
935 // Add your data source here, in alphabetical order.
936 if (source_name_ == chrome::kChromeUIChromeURLsHost) {
937 response = ChromeURLs();
938 } else if (source_name_ == chrome::kChromeUICreditsHost) {
939 int idr = IDR_CREDITS_HTML;
940 if (path == kCreditsJsPath)
941 idr = IDR_CREDITS_JS;
942 #if defined(OS_CHROMEOS)
943 else if (path == kKeyboardUtilsPath)
944 idr = IDR_KEYBOARD_UTILS_JS;
945 #endif
947 response = ResourceBundle::GetSharedInstance().GetRawDataResource(
948 idr).as_string();
949 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
950 } else if (source_name_ == chrome::kChromeUIDiscardsHost) {
951 response = AboutDiscards(path);
952 #endif
953 } else if (source_name_ == chrome::kChromeUIDNSHost) {
954 AboutDnsHandler::Start(profile(), callback);
955 return;
956 #if defined(OS_LINUX) || defined(OS_OPENBSD)
957 } else if (source_name_ == chrome::kChromeUILinuxProxyConfigHost) {
958 response = AboutLinuxProxyConfig();
959 #endif
960 } else if (source_name_ == chrome::kChromeUIMemoryHost) {
961 response = GetAboutMemoryRedirectResponse(profile());
962 } else if (source_name_ == chrome::kChromeUIMemoryRedirectHost) {
963 FinishMemoryDataRequest(path, callback);
964 return;
965 #if defined(OS_CHROMEOS)
966 } else if (source_name_ == chrome::kChromeUIOSCreditsHost) {
967 ChromeOSCreditsHandler::Start(path, callback);
968 return;
969 #endif
970 #if defined(OS_LINUX) || defined(OS_OPENBSD)
971 } else if (source_name_ == chrome::kChromeUISandboxHost) {
972 response = AboutSandbox();
973 #endif
974 #if !defined(OS_ANDROID)
975 } else if (source_name_ == chrome::kChromeUITermsHost) {
976 #if defined(OS_CHROMEOS)
977 ChromeOSTermsHandler::Start(path, callback);
978 return;
979 #else
980 response = l10n_util::GetStringUTF8(IDS_TERMS_HTML);
981 #endif
982 #endif
985 FinishDataRequest(response, callback);
988 void AboutUIHTMLSource::FinishDataRequest(
989 const std::string& html,
990 const content::URLDataSource::GotDataCallback& callback) {
991 std::string html_copy(html);
992 callback.Run(base::RefCountedString::TakeString(&html_copy));
995 std::string AboutUIHTMLSource::GetMimeType(const std::string& path) const {
996 if (path == kCreditsJsPath ||
997 #if defined(OS_CHROMEOS)
998 path == kKeyboardUtilsPath ||
999 #endif
1000 path == kStatsJsPath ||
1001 path == kStringsJsPath ||
1002 path == kMemoryJsPath) {
1003 return "application/javascript";
1005 return "text/html";
1008 bool AboutUIHTMLSource::ShouldAddContentSecurityPolicy() const {
1009 #if defined(OS_CHROMEOS)
1010 if (source_name_ == chrome::kChromeUIOSCreditsHost)
1011 return false;
1012 #endif
1013 return content::URLDataSource::ShouldAddContentSecurityPolicy();
1016 bool AboutUIHTMLSource::ShouldDenyXFrameOptions() const {
1017 #if defined(OS_CHROMEOS)
1018 if (source_name_ == chrome::kChromeUITermsHost) {
1019 // chrome://terms page is embedded in iframe to chrome://oobe.
1020 return false;
1022 #endif
1023 return content::URLDataSource::ShouldDenyXFrameOptions();
1026 AboutUI::AboutUI(content::WebUI* web_ui, const std::string& name)
1027 : WebUIController(web_ui) {
1028 Profile* profile = Profile::FromWebUI(web_ui);
1030 #if defined(ENABLE_THEMES)
1031 // Set up the chrome://theme/ source.
1032 ThemeSource* theme = new ThemeSource(profile);
1033 content::URLDataSource::Add(profile, theme);
1034 #endif
1036 content::URLDataSource::Add(profile, new AboutUIHTMLSource(name, profile));