177a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt// Copyright (c) 2012 The Chromium Authors. All rights reserved.
277a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt// Use of this source code is governed by a BSD-style license that can be
377a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt// found in the LICENSE file.
477a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt
577a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt#include "chrome/browser/ui/webui/about_ui.h"
677a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt
777a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt#include <algorithm>
877a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt#include <string>
977a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt#include <utility>
1077a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt#include <vector>
1177a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt
1277a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt#include "base/bind.h"
1377a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt#include "base/bind_helpers.h"
1477a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt#include "base/callback.h"
1577a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt#include "base/command_line.h"
1677a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt#include "base/file_util.h"
1777a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt#include "base/i18n/number_formatting.h"
1877a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt#include "base/json/json_writer.h"
1977a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt#include "base/memory/singleton.h"
2077a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt#include "base/metrics/statistics_recorder.h"
2177a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt#include "base/metrics/stats_table.h"
2277a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt#include "base/path_service.h"
2377a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt#include "base/strings/string_number_conversions.h"
2477a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt#include "base/strings/string_piece.h"
2577a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt#include "base/strings/string_util.h"
2677a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt#include "base/strings/stringprintf.h"
2777a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt#include "base/strings/utf_string_conversions.h"
28f6ca4a304bf920ea6913b08638fb8eb3e020d446Eric Anholt#include "base/threading/thread.h"
29ecadb51bbcb972a79f3ed79e65a7986b9396e757Brian Paul#include "base/values.h"
30ecadb51bbcb972a79f3ed79e65a7986b9396e757Brian Paul#include "chrome/browser/about_flags.h"
31ecadb51bbcb972a79f3ed79e65a7986b9396e757Brian Paul#include "chrome/browser/browser_process.h"
32ecadb51bbcb972a79f3ed79e65a7986b9396e757Brian Paul#include "chrome/browser/defaults.h"
332d99588b3556928a0879b4160210ac771dbf1f0bKristian Høgsberg#include "chrome/browser/memory_details.h"
34d7322c9d420e484bc3c7cecb873b04cf7da7f33aKristian Høgsberg#include "chrome/browser/net/predictor.h"
3545a56e4730a74a012ad712fd9b6013d900b04742Vinson Lee#include "chrome/browser/profiles/profile.h"
366c244b0f326504ae6add1ddcb407e73c3e72da78Brian Paul#include "chrome/browser/profiles/profile_manager.h"
3777a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt#include "chrome/browser/ui/browser_dialogs.h"
3877a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt#include "chrome/common/chrome_paths.h"
3977a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt#include "chrome/common/net/url_fixer_upper.h"
4077a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt#include "chrome/common/render_messages.h"
41a0e453a5eca7ed4b57a7f4c1e418d368815e3957Eric Anholt#include "chrome/common/url_constants.h"
42a0e453a5eca7ed4b57a7f4c1e418d368815e3957Eric Anholt#include "content/public/browser/browser_thread.h"
43e9bf3e4cc9a7e4bcd4c45bd707541d26ecdf0409Jesse Barnes#include "content/public/browser/render_process_host.h"
44fe91c05b5494b889c8adda77ff562712116d2e59Eric Anholt#include "content/public/browser/render_view_host.h"
45fe91c05b5494b889c8adda77ff562712116d2e59Eric Anholt#include "content/public/browser/url_data_source.h"
46fe91c05b5494b889c8adda77ff562712116d2e59Eric Anholt#include "content/public/browser/web_contents.h"
47f75843a517bd188639e6866db2a7b04de3524e16Dave Airlie#include "content/public/common/content_client.h"
48fe91c05b5494b889c8adda77ff562712116d2e59Eric Anholt#include "content/public/common/process_type.h"
49fe91c05b5494b889c8adda77ff562712116d2e59Eric Anholt#include "google_apis/gaia/google_service_auth_error.h"
50fe91c05b5494b889c8adda77ff562712116d2e59Eric Anholt#include "grit/browser_resources.h"
51fe91c05b5494b889c8adda77ff562712116d2e59Eric Anholt#include "grit/chromium_strings.h"
52fe91c05b5494b889c8adda77ff562712116d2e59Eric Anholt#include "grit/generated_resources.h"
531ba96651e12b3c74fb9c8f5a61b183ef36a27b1eEric Anholt#include "grit/locale_settings.h"
548e7a8d65931a650534e0f5c4e0d8118cd6f7636eEric Anholt#include "net/base/escape.h"
558e7a8d65931a650534e0f5c4e0d8118cd6f7636eEric Anholt#include "net/base/load_flags.h"
568e7a8d65931a650534e0f5c4e0d8118cd6f7636eEric Anholt#include "net/base/net_util.h"
571ba96651e12b3c74fb9c8f5a61b183ef36a27b1eEric Anholt#include "net/http/http_response_headers.h"
58b30dc2c66aeaad6661eef515a08a3da89aa07cb2Eric Anholt#include "net/url_request/url_fetcher.h"
59b30dc2c66aeaad6661eef515a08a3da89aa07cb2Eric Anholt#include "net/url_request/url_request_status.h"
60b30dc2c66aeaad6661eef515a08a3da89aa07cb2Eric Anholt#include "ui/base/l10n/l10n_util.h"
61b30dc2c66aeaad6661eef515a08a3da89aa07cb2Eric Anholt#include "ui/base/resource/resource_bundle.h"
62a58514cc9c5cc5867f9140700462c5ac5749550dEric Anholt#include "ui/base/webui/jstemplate_builder.h"
63862a2a55b35d1dec9224b025a6e7a0cf8593a6a7Eric Anholt#include "ui/base/webui/web_ui_util.h"
64862a2a55b35d1dec9224b025a6e7a0cf8593a6a7Eric Anholt#include "url/gurl.h"
65862a2a55b35d1dec9224b025a6e7a0cf8593a6a7Eric Anholt
66a0e453a5eca7ed4b57a7f4c1e418d368815e3957Eric Anholt#if defined(ENABLE_THEMES)
67a0e453a5eca7ed4b57a7f4c1e418d368815e3957Eric Anholt#include "chrome/browser/ui/webui/theme_source.h"
68a0e453a5eca7ed4b57a7f4c1e418d368815e3957Eric Anholt#endif
69acba9c1771d653126fd6f604cb80c050b9e8ffb3Michel Dänzer
70a0e453a5eca7ed4b57a7f4c1e418d368815e3957Eric Anholt#if defined(OS_LINUX) || defined(OS_OPENBSD)
71a0e453a5eca7ed4b57a7f4c1e418d368815e3957Eric Anholt#include "content/public/browser/zygote_host_linux.h"
72a0e453a5eca7ed4b57a7f4c1e418d368815e3957Eric Anholt#include "content/public/common/sandbox_linux.h"
7340bc2748c2781600c748e546160bcc2aab637825Eric Anholt#endif
74f3687284c12f34268172b9c60e2effd697162129Eric Anholt
7581aa5d717bd0098608e9cc292b316293800c7e11Eric Anholt#if defined(OS_WIN)
7681aa5d717bd0098608e9cc292b316293800c7e11Eric Anholt#include "chrome/browser/enumerate_modules_model_win.h"
7781aa5d717bd0098608e9cc292b316293800c7e11Eric Anholt#endif
7881aa5d717bd0098608e9cc292b316293800c7e11Eric Anholt
79a0e453a5eca7ed4b57a7f4c1e418d368815e3957Eric Anholt#if defined(OS_CHROMEOS)
80a0e453a5eca7ed4b57a7f4c1e418d368815e3957Eric Anholt#include "chrome/browser/browser_process_platform_part_chromeos.h"
81a0e453a5eca7ed4b57a7f4c1e418d368815e3957Eric Anholt#include "chrome/browser/chromeos/customization_document.h"
821e4677a61f0576c32e65e9202fa08e81e1162f65Eric Anholt#include "chrome/browser/chromeos/memory/oom_priority_manager.h"
8377a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt#include "chromeos/chromeos_switches.h"
84df9f89154471ec162227ebce1681c5010f64e6e6Eric Anholt#endif
85df9f89154471ec162227ebce1681c5010f64e6e6Eric Anholt
86df9f89154471ec162227ebce1681c5010f64e6e6Eric Anholtusing base::Time;
87df9f89154471ec162227ebce1681c5010f64e6e6Eric Anholtusing base::TimeDelta;
88df9f89154471ec162227ebce1681c5010f64e6e6Eric Anholtusing content::BrowserThread;
89df9f89154471ec162227ebce1681c5010f64e6e6Eric Anholtusing content::WebContents;
90df9f89154471ec162227ebce1681c5010f64e6e6Eric Anholt
91df9f89154471ec162227ebce1681c5010f64e6e6Eric Anholtnamespace {
92df9f89154471ec162227ebce1681c5010f64e6e6Eric Anholt
93df9f89154471ec162227ebce1681c5010f64e6e6Eric Anholtconst char kCreditsJsPath[] = "credits.js";
94df9f89154471ec162227ebce1681c5010f64e6e6Eric Anholtconst char kMemoryJsPath[] = "memory.js";
9577a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholtconst char kMemoryCssPath[] = "about_memory.css";
9685063f14ea431b586d710f249563fc73481552c7Eric Anholtconst char kStatsJsPath[] = "stats.js";
9777a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholtconst char kStringsJsPath[] = "strings.js";
9877a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt
996d48779c7e5c9002d1bec4b1266ca05a474218efKristian Høgsberg#if defined(OS_CHROMEOS)
1006d48779c7e5c9002d1bec4b1266ca05a474218efKristian Høgsberg// chrome://terms falls back to offline page after kOnlineTermsTimeoutSec.
1016d48779c7e5c9002d1bec4b1266ca05a474218efKristian Høgsbergconst int kOnlineTermsTimeoutSec = 7;
10266175aac7609ad314f25fbdff0d3958af310dc24Eric Anholt#endif  // defined(OS_CHROMEOS)
1036d48779c7e5c9002d1bec4b1266ca05a474218efKristian Høgsberg
1046d48779c7e5c9002d1bec4b1266ca05a474218efKristian Høgsberg// When you type about:memory, it actually loads this intermediate URL that
1057c50d29f7ced3d60e52ee0146d982b49ea421de2Kristian Høgsberg// redirects you to the final page. This avoids the problem where typing
1067c50d29f7ced3d60e52ee0146d982b49ea421de2Kristian Høgsberg// "about:memory" on the new tab page or any other page where a process
1077c50d29f7ced3d60e52ee0146d982b49ea421de2Kristian Høgsberg// transition would occur to the about URL will cause some confusion.
108dea5e57861ec998cb7ee913a8819752cb9fa946bEric Anholt//
109dea5e57861ec998cb7ee913a8819752cb9fa946bEric Anholt// The problem is that during the processing of the memory page, there are two
1107c50d29f7ced3d60e52ee0146d982b49ea421de2Kristian Høgsberg// processes active, the original and the destination one. This can create the
1117c50d29f7ced3d60e52ee0146d982b49ea421de2Kristian Høgsberg// impression that we're using more resources than we actually are. This
1127c50d29f7ced3d60e52ee0146d982b49ea421de2Kristian Høgsberg// redirect solves the problem by eliminating the process transition during the
1137c50d29f7ced3d60e52ee0146d982b49ea421de2Kristian Høgsberg// time that about memory is being computed.
1142e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunkestd::string GetAboutMemoryRedirectResponse(Profile* profile) {
115e67c338b415c983bee570e6644b9684d8d1fc99bKristian Høgsberg  return base::StringPrintf("<meta http-equiv='refresh' content='0;%s'>",
1168d68a90e225d831a395ba788e425cb717eec1f9aChris Wilson                            chrome::kChromeUIMemoryRedirectURL);
1178d68a90e225d831a395ba788e425cb717eec1f9aChris Wilson}
1187c50d29f7ced3d60e52ee0146d982b49ea421de2Kristian Høgsberg
1197c50d29f7ced3d60e52ee0146d982b49ea421de2Kristian Høgsberg// Handling about:memory is complicated enough to encapsulate its related
1207c50d29f7ced3d60e52ee0146d982b49ea421de2Kristian Høgsberg// methods into a single class. The user should create it (on the heap) and call
1217c50d29f7ced3d60e52ee0146d982b49ea421de2Kristian Høgsberg// its |StartFetch()| method.
1227c50d29f7ced3d60e52ee0146d982b49ea421de2Kristian Høgsbergclass AboutMemoryHandler : public MemoryDetails {
123e67c338b415c983bee570e6644b9684d8d1fc99bKristian Høgsberg public:
1247c50d29f7ced3d60e52ee0146d982b49ea421de2Kristian Høgsberg  explicit AboutMemoryHandler(
1257c50d29f7ced3d60e52ee0146d982b49ea421de2Kristian Høgsberg      const content::URLDataSource::GotDataCallback& callback)
126c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg      : callback_(callback) {
1279ec0b2a45e18c045fd3dbcdf846fad7faf97494cKristian Høgsberg  }
128c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg
129c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg  virtual void OnDetailsAvailable() OVERRIDE;
130c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg
1319ec0b2a45e18c045fd3dbcdf846fad7faf97494cKristian Høgsberg private:
132c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg  virtual ~AboutMemoryHandler() {}
133c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg
134c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg  void BindProcessMetrics(DictionaryValue* data,
135c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg                          ProcessMemoryInformation* info);
136c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg  void AppendProcess(ListValue* child_data, ProcessMemoryInformation* info);
137c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg
138c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg  content::URLDataSource::GotDataCallback callback_;
139c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg
140c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg  DISALLOW_COPY_AND_ASSIGN(AboutMemoryHandler);
141c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg};
142c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg
143c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg#if defined(OS_CHROMEOS)
144c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg
145c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg// Helper class that fetches the online Chrome OS terms. Empty string is
146c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg// returned once fetching failed or exceeded |kOnlineTermsTimeoutSec|.
147c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsbergclass ChromeOSOnlineTermsHandler : public net::URLFetcherDelegate {
148c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg public:
149c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg  typedef base::Callback<void (ChromeOSOnlineTermsHandler*)> FetchCallback;
150c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg
151c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg  explicit ChromeOSOnlineTermsHandler(const FetchCallback& callback,
152c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg                                      const std::string& locale)
153c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg      : fetch_callback_(callback) {
154c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg    std::string eula_URL = base::StringPrintf(chrome::kOnlineEulaURLPath,
1559fe197c62611815ebe74248033271ad9fd07ae06Chia-I Wu                                              locale.c_str());
1569fe197c62611815ebe74248033271ad9fd07ae06Chia-I Wu    eula_fetcher_.reset(net::URLFetcher::Create(0 /* ID used for testing */,
1579fe197c62611815ebe74248033271ad9fd07ae06Chia-I Wu                                                GURL(eula_URL),
1589fe197c62611815ebe74248033271ad9fd07ae06Chia-I Wu                                                net::URLFetcher::GET,
1599fe197c62611815ebe74248033271ad9fd07ae06Chia-I Wu                                                this));
160c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg    eula_fetcher_->SetRequestContext(
161c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg        g_browser_process->system_request_context());
162c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg    eula_fetcher_->AddExtraRequestHeader("Accept: text/html");
163c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg    eula_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
164c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg                                net::LOAD_DO_NOT_SAVE_COOKIES |
165c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg                                net::LOAD_DISABLE_CACHE);
166c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg    eula_fetcher_->Start();
167c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg    // Abort the download attempt if it takes longer than one minute.
1689ec0b2a45e18c045fd3dbcdf846fad7faf97494cKristian Høgsberg    download_timer_.Start(FROM_HERE,
1699087ba128089ed0dc00e6eb38f37126fb7557d3bKristian Høgsberg                          base::TimeDelta::FromSeconds(kOnlineTermsTimeoutSec),
170c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg                          this,
171c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg                          &ChromeOSOnlineTermsHandler::OnDownloadTimeout);
172c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg  }
173c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg
174c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg  void GetResponseResult(std::string* response_string) {
175c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg    std::string mime_type;
176c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg    if (!eula_fetcher_ ||
177c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg        !eula_fetcher_->GetStatus().is_success() ||
178c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg        eula_fetcher_->GetResponseCode() != 200 ||
179c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg        !eula_fetcher_->GetResponseHeaders()->GetMimeType(&mime_type) ||
180c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg        mime_type != "text/html" ||
181c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg        !eula_fetcher_->GetResponseAsString(response_string)) {
182c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg      response_string->clear();
183c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg    }
184c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg  }
185c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg
186c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg private:
187c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg  // Prevents allocation on the stack. ChromeOSOnlineTermsHandler should be
188d7322c9d420e484bc3c7cecb873b04cf7da7f33aKristian Høgsberg  // created by 'operator new'. |this| takes care of destruction.
189c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg  virtual ~ChromeOSOnlineTermsHandler() {}
190c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg
191c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg  // net::URLFetcherDelegate:
192c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg  virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE {
193c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg    if (source != eula_fetcher_.get()) {
194c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg      NOTREACHED() << "Callback from foreign URL fetcher";
195c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg      return;
196c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg    }
197c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg    fetch_callback_.Run(this);
198c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg    delete this;
199c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg  }
200c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg
201c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg  void OnDownloadTimeout() {
202c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg    eula_fetcher_.reset();
203c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg    fetch_callback_.Run(this);
204c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg    delete this;
205c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg  }
206c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg
207c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg  // Timer that enforces a timeout on the attempt to download the
208c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg  // ChromeOS Terms.
209c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg  base::OneShotTimer<ChromeOSOnlineTermsHandler> download_timer_;
210c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg
211c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg  // |fetch_callback_| called when fetching succeeded or failed.
212c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg  FetchCallback fetch_callback_;
213c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg
214c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg  // Helper to fetch online eula.
215c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg  scoped_ptr<net::URLFetcher> eula_fetcher_;
216f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg
217f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg  DISALLOW_COPY_AND_ASSIGN(ChromeOSOnlineTermsHandler);
218f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg};
219f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg
220f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsbergclass ChromeOSTermsHandler
221f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg    : public base::RefCountedThreadSafe<ChromeOSTermsHandler> {
222f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg public:
223f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg  static void Start(const std::string& path,
224e5169e9615e8391ea369415b356168717b8f7be0Kristian Høgsberg                    const content::URLDataSource::GotDataCallback& callback) {
225f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg    scoped_refptr<ChromeOSTermsHandler> handler(
226f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg        new ChromeOSTermsHandler(path, callback));
227e5169e9615e8391ea369415b356168717b8f7be0Kristian Høgsberg    handler->StartOnUIThread();
228e5169e9615e8391ea369415b356168717b8f7be0Kristian Høgsberg  }
229e5169e9615e8391ea369415b356168717b8f7be0Kristian Høgsberg
230e5169e9615e8391ea369415b356168717b8f7be0Kristian Høgsberg private:
231e5169e9615e8391ea369415b356168717b8f7be0Kristian Høgsberg  friend class base::RefCountedThreadSafe<ChromeOSTermsHandler>;
232e5169e9615e8391ea369415b356168717b8f7be0Kristian Høgsberg
233e5169e9615e8391ea369415b356168717b8f7be0Kristian Høgsberg  ChromeOSTermsHandler(const std::string& path,
234f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg                       const content::URLDataSource::GotDataCallback& callback)
235f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg    : path_(path),
236f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg      callback_(callback),
237f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg      // Previously we were using "initial locale" http://crbug.com/145142
238f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg      locale_(g_browser_process->GetApplicationLocale()) {
239f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg  }
240f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg
241f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg  virtual ~ChromeOSTermsHandler() {}
242f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg
243f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg  void StartOnUIThread() {
244f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
245f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg    if (path_ == chrome::kOemEulaURLPath) {
246f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg      // Load local OEM EULA from the disk.
247f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg      BrowserThread::PostTask(
248f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg          BrowserThread::FILE, FROM_HERE,
249f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg          base::Bind(&ChromeOSTermsHandler::LoadOemEulaFileOnFileThread, this));
250f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg    } else if (CommandLine::ForCurrentProcess()->HasSwitch(
251f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg                   chromeos::switches::kDisableOnlineEULA)) {
252f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg      // Fallback to the local file.
253f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg      BrowserThread::PostTask(
2549fe197c62611815ebe74248033271ad9fd07ae06Chia-I Wu          BrowserThread::FILE, FROM_HERE,
2559fe197c62611815ebe74248033271ad9fd07ae06Chia-I Wu          base::Bind(&ChromeOSTermsHandler::LoadEulaFileOnFileThread, this));
2569fe197c62611815ebe74248033271ad9fd07ae06Chia-I Wu    } else {
2579fe197c62611815ebe74248033271ad9fd07ae06Chia-I Wu      // Try to load online version of ChromeOS terms first.
2589fe197c62611815ebe74248033271ad9fd07ae06Chia-I Wu      // ChromeOSOnlineTermsHandler object destroys itself.
259f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg      new ChromeOSOnlineTermsHandler(
260f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg          base::Bind(&ChromeOSTermsHandler::OnOnlineEULAFetched, this),
261f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg          locale_);
262f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg    }
263f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg  }
264f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg
265f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg  void OnOnlineEULAFetched(ChromeOSOnlineTermsHandler* loader) {
266f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
267f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg    loader->GetResponseResult(&contents_);
268e5169e9615e8391ea369415b356168717b8f7be0Kristian Høgsberg    if (contents_.empty()) {
2692e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke      // Load local ChromeOS terms from the file.
270f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg      BrowserThread::PostTask(
271f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg          BrowserThread::FILE, FROM_HERE,
272f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg          base::Bind(&ChromeOSTermsHandler::LoadEulaFileOnFileThread, this));
273f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg    } else {
274f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg      ResponseOnUIThread();
275f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg    }
276f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg  }
277f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg
278f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg  void LoadOemEulaFileOnFileThread() {
279f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
280f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg    const chromeos::StartupCustomizationDocument* customization =
281f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg        chromeos::StartupCustomizationDocument::GetInstance();
282f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg    if (customization->IsReady()) {
283f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg      base::FilePath oem_eula_file_path;
2842e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke      if (net::FileURLToFilePath(GURL(customization->GetEULAPage(locale_)),
285f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg                                 &oem_eula_file_path)) {
2868004a1cb95b8a195f3f4bbaa8d39d2f3297167deEric Anholt        if (!base::ReadFileToString(oem_eula_file_path, &contents_)) {
2872e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke          contents_.clear();
288f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg        }
289f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg      }
290f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg    }
2912e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke    BrowserThread::PostTask(
292f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg        BrowserThread::UI, FROM_HERE,
293f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg        base::Bind(&ChromeOSTermsHandler::ResponseOnUIThread, this));
294f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg  }
2953af3c58dfd8b1ddc96fc10b6865de0cb26860ddeBenjamin Franzke
2963af3c58dfd8b1ddc96fc10b6865de0cb26860ddeBenjamin Franzke  void LoadEulaFileOnFileThread() {
2973af3c58dfd8b1ddc96fc10b6865de0cb26860ddeBenjamin Franzke    std::string file_path =
2983af3c58dfd8b1ddc96fc10b6865de0cb26860ddeBenjamin Franzke        base::StringPrintf(chrome::kEULAPathFormat, locale_.c_str());
2993af3c58dfd8b1ddc96fc10b6865de0cb26860ddeBenjamin Franzke    if (!base::ReadFileToString(base::FilePath(file_path), &contents_)) {
3003af3c58dfd8b1ddc96fc10b6865de0cb26860ddeBenjamin Franzke      // No EULA for given language - try en-US as default.
3013af3c58dfd8b1ddc96fc10b6865de0cb26860ddeBenjamin Franzke      file_path = base::StringPrintf(chrome::kEULAPathFormat, "en-US");
3023af3c58dfd8b1ddc96fc10b6865de0cb26860ddeBenjamin Franzke      if (!base::ReadFileToString(base::FilePath(file_path), &contents_)) {
3033af3c58dfd8b1ddc96fc10b6865de0cb26860ddeBenjamin Franzke        // File with EULA not found, ResponseOnUIThread will load EULA from
3043af3c58dfd8b1ddc96fc10b6865de0cb26860ddeBenjamin Franzke        // resources if contents_ is empty.
3053af3c58dfd8b1ddc96fc10b6865de0cb26860ddeBenjamin Franzke        contents_.clear();
3063af3c58dfd8b1ddc96fc10b6865de0cb26860ddeBenjamin Franzke      }
3073af3c58dfd8b1ddc96fc10b6865de0cb26860ddeBenjamin Franzke    }
3083af3c58dfd8b1ddc96fc10b6865de0cb26860ddeBenjamin Franzke    BrowserThread::PostTask(
3093af3c58dfd8b1ddc96fc10b6865de0cb26860ddeBenjamin Franzke        BrowserThread::UI, FROM_HERE,
3103af3c58dfd8b1ddc96fc10b6865de0cb26860ddeBenjamin Franzke        base::Bind(&ChromeOSTermsHandler::ResponseOnUIThread, this));
3113af3c58dfd8b1ddc96fc10b6865de0cb26860ddeBenjamin Franzke  }
3123af3c58dfd8b1ddc96fc10b6865de0cb26860ddeBenjamin Franzke
3133af3c58dfd8b1ddc96fc10b6865de0cb26860ddeBenjamin Franzke  void ResponseOnUIThread() {
3143af3c58dfd8b1ddc96fc10b6865de0cb26860ddeBenjamin Franzke    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3153af3c58dfd8b1ddc96fc10b6865de0cb26860ddeBenjamin Franzke    // If we fail to load Chrome OS EULA from disk, load it from resources.
3163af3c58dfd8b1ddc96fc10b6865de0cb26860ddeBenjamin Franzke    // Do nothing if OEM EULA load failed.
3173af3c58dfd8b1ddc96fc10b6865de0cb26860ddeBenjamin Franzke    if (contents_.empty() && path_ != chrome::kOemEulaURLPath)
318c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg      contents_ = l10n_util::GetStringUTF8(IDS_TERMS_HTML);
319c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg    callback_.Run(base::RefCountedString::TakeString(&contents_));
320c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg  }
321c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg
322c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg  // Path in the URL.
323f301932dba4cc75e810e0c051e39247128a899fcKristian Høgsberg  const std::string path_;
3243af3c58dfd8b1ddc96fc10b6865de0cb26860ddeBenjamin Franzke
3253af3c58dfd8b1ddc96fc10b6865de0cb26860ddeBenjamin Franzke  // Callback to run with the response.
326c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg  content::URLDataSource::GotDataCallback callback_;
327c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg
328e82dd8c6e1fa2fff5b960de26961080ba5e9651dKristian Høgsberg  // Locale of the EULA.
3296d48779c7e5c9002d1bec4b1266ca05a474218efKristian Høgsberg  const std::string locale_;
3307c50d29f7ced3d60e52ee0146d982b49ea421de2Kristian Høgsberg
331c26247100bfd453a7ec013f630abe366c12fbd8bKristian Høgsberg  // EULA contents that was loaded from file.
332234286c0f8b7d30ed49223c648d4c73c1a517ab3Jesse Barnes  std::string contents_;
33377a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt
33477a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt  DISALLOW_COPY_AND_ASSIGN(ChromeOSTermsHandler);
33577a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt};
3362e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke
337d61f07318c8678901b948fdaa8ccdf37aa3203e9Kristian Høgsberg#endif
33824e7e457680d700e986fd0b0e0f046fadf67caf4Kristian Høgsberg
33924e7e457680d700e986fd0b0e0f046fadf67caf4Kristian Høgsberg}  // namespace
3401c718c0d78cf4eae9e02b03a0abbec384db948a6Alan Hourihane
34124e7e457680d700e986fd0b0e0f046fadf67caf4Kristian Høgsberg// Individual about handlers ---------------------------------------------------
34224e7e457680d700e986fd0b0e0f046fadf67caf4Kristian Høgsberg
34324e7e457680d700e986fd0b0e0f046fadf67caf4Kristian Høgsbergnamespace about_ui {
34424e7e457680d700e986fd0b0e0f046fadf67caf4Kristian Høgsberg
3451c718c0d78cf4eae9e02b03a0abbec384db948a6Alan Hourihanevoid AppendHeader(std::string* output, int refresh,
34624e7e457680d700e986fd0b0e0f046fadf67caf4Kristian Høgsberg                  const std::string& unescaped_title) {
347f6ca4a304bf920ea6913b08638fb8eb3e020d446Eric Anholt  output->append("<!DOCTYPE HTML>\n<html>\n<head>\n");
348f6ca4a304bf920ea6913b08638fb8eb3e020d446Eric Anholt  if (!unescaped_title.empty()) {
3492e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke    output->append("<title>");
35024e7e457680d700e986fd0b0e0f046fadf67caf4Kristian Høgsberg    output->append(net::EscapeForHTML(unescaped_title));
35124e7e457680d700e986fd0b0e0f046fadf67caf4Kristian Høgsberg    output->append("</title>\n");
3522e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke  }
35324e7e457680d700e986fd0b0e0f046fadf67caf4Kristian Høgsberg  output->append("<meta charset='utf-8'>\n");
35477a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt  if (refresh > 0) {
3552e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke    output->append("<meta http-equiv='refresh' content='");
356900a5c91eeb3acae7ee0ad331154531c4dba96e1Chris Wilson    output->append(base::IntToString(refresh));
357900a5c91eeb3acae7ee0ad331154531c4dba96e1Chris Wilson    output->append("'/>\n");
358900a5c91eeb3acae7ee0ad331154531c4dba96e1Chris Wilson  }
359900a5c91eeb3acae7ee0ad331154531c4dba96e1Chris Wilson}
360900a5c91eeb3acae7ee0ad331154531c4dba96e1Chris Wilson
361900a5c91eeb3acae7ee0ad331154531c4dba96e1Chris Wilsonvoid AppendBody(std::string *output) {
36277a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt  output->append("</head>\n<body>\n");
3632d99588b3556928a0879b4160210ac771dbf1f0bKristian Høgsberg}
3642d99588b3556928a0879b4160210ac771dbf1f0bKristian Høgsberg
3652d99588b3556928a0879b4160210ac771dbf1f0bKristian Høgsbergvoid AppendFooter(std::string *output) {
3662d99588b3556928a0879b4160210ac771dbf1f0bKristian Høgsberg  output->append("</body>\n</html>\n");
3672d99588b3556928a0879b4160210ac771dbf1f0bKristian Høgsberg}
368d61f07318c8678901b948fdaa8ccdf37aa3203e9Kristian Høgsberg
36977a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt}  // namespace about_ui
3705777dee02c6497207e6b4b9d68de072e7be7c06eKristian Høgsberg
37177a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholtusing about_ui::AppendHeader;
372904f31a62444d9f7e9b12ddafaa4beeb7fed6dfaEric Anholtusing about_ui::AppendBody;
3736d66f23c50ebe8f973757b6fd1b81c9b7920c447Eric Anholtusing about_ui::AppendFooter;
37477a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt
3752d99588b3556928a0879b4160210ac771dbf1f0bKristian Høgsbergnamespace {
3762d99588b3556928a0879b4160210ac771dbf1f0bKristian Høgsberg
3772d99588b3556928a0879b4160210ac771dbf1f0bKristian Høgsbergstd::string ChromeURLs() {
3782d99588b3556928a0879b4160210ac771dbf1f0bKristian Høgsberg  std::string html;
3792d99588b3556928a0879b4160210ac771dbf1f0bKristian Høgsberg  AppendHeader(&html, 0, "Chrome URLs");
3802d99588b3556928a0879b4160210ac771dbf1f0bKristian Høgsberg  AppendBody(&html);
38177a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt  html += "<h2>List of Chrome URLs</h2>\n<ul>\n";
38277a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt  std::vector<std::string> hosts(
38377a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt      chrome::kChromeHostURLs,
38477a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt      chrome::kChromeHostURLs + chrome::kNumberOfChromeHostURLs);
38577a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt  std::sort(hosts.begin(), hosts.end());
38677a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt  for (std::vector<std::string>::const_iterator i = hosts.begin();
38777a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt       i != hosts.end(); ++i)
38877a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt    html += "<li><a href='chrome://" + *i + "/'>chrome://" + *i + "</a></li>\n";
38977a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt  html += "</ul>\n<h2>For Debug</h2>\n"
390d61f07318c8678901b948fdaa8ccdf37aa3203e9Kristian Høgsberg      "<p>The following pages are for debugging purposes only. Because they "
391d61f07318c8678901b948fdaa8ccdf37aa3203e9Kristian Høgsberg      "crash or hang the renderer, they're not linked directly; you can type "
392d3491e775fb07f891463b2185d74bbad62f3ed24Kristian Høgsberg      "them into the address bar if you need them.</p>\n<ul>";
39377a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt  for (int i = 0; i < chrome::kNumberOfChromeDebugURLs; i++)
394d282128ff68cc58bc3f5b808031c5fe7325bd69bKristian Høgsberg    html += "<li>" + std::string(chrome::kChromeDebugURLs[i]) + "</li>\n";
395aea2236af60aee329e6ea73a41f2410d8eacc7b6Chad Versace  html += "</ul>\n";
396d282128ff68cc58bc3f5b808031c5fe7325bd69bKristian Høgsberg  AppendFooter(&html);
39777a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt  return html;
3982e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke}
39977a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt
40077a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt#if defined(OS_CHROMEOS)
4014a253431abf43a0638afb43605b44a8742b72a60Brian Paul
40277a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt// Html output helper functions
403d282128ff68cc58bc3f5b808031c5fe7325bd69bKristian Høgsberg
40477a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt// Helper function to wrap HTML with a tag.
405d282128ff68cc58bc3f5b808031c5fe7325bd69bKristian Høgsbergstd::string WrapWithTag(const std::string& tag, const std::string& text) {
4062e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke  return "<" + tag + ">" + text + "</" + tag + ">";
40777a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt}
4082ec50d256d49ff3b987459ed42a5dc66f02a6b9dFrancisco Jerez
40977a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt// Helper function to wrap Html with <td> tag.
410119f34e2a52d7e074ea51d49acf6c11d83142cccEric Anholtstd::string WrapWithTD(const std::string& text) {
4114a253431abf43a0638afb43605b44a8742b72a60Brian Paul  return "<td>" + text + "</td>";
412119f34e2a52d7e074ea51d49acf6c11d83142cccEric Anholt}
413409469fb70682cd819ab405e0f92a4659381cfbeBrian Paul
414119f34e2a52d7e074ea51d49acf6c11d83142cccEric Anholt// Helper function to wrap Html with <tr> tag.
4154a253431abf43a0638afb43605b44a8742b72a60Brian Paulstd::string WrapWithTR(const std::string& text) {
416119f34e2a52d7e074ea51d49acf6c11d83142cccEric Anholt  return "<tr>" + text + "</tr>";
41777a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt}
418d282128ff68cc58bc3f5b808031c5fe7325bd69bKristian Høgsberg
419d282128ff68cc58bc3f5b808031c5fe7325bd69bKristian Høgsbergstd::string AddStringRow(const std::string& name, const std::string& value) {
42077a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt  std::string row;
42177a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt  row.append(WrapWithTD(name));
422d282128ff68cc58bc3f5b808031c5fe7325bd69bKristian Høgsberg  row.append(WrapWithTD(value));
423d282128ff68cc58bc3f5b808031c5fe7325bd69bKristian Høgsberg  return WrapWithTR(row);
42477a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt}
42577a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt
426f4efb7ff4f9cb0f6386e9b53f4dcfd9ef23dc9d1Chad Versacevoid AddContentSecurityPolicy(std::string* output) {
427f4efb7ff4f9cb0f6386e9b53f4dcfd9ef23dc9d1Chad Versace  output->append("<meta http-equiv='Content-Security-Policy' "
428f4efb7ff4f9cb0f6386e9b53f4dcfd9ef23dc9d1Chad Versace      "content='default-src 'none';'>");
429f4efb7ff4f9cb0f6386e9b53f4dcfd9ef23dc9d1Chad Versace}
430f4efb7ff4f9cb0f6386e9b53f4dcfd9ef23dc9d1Chad Versace
43138c616260a4c14bf5a1d7831e6349c3e8817d14bEric Anholt// TODO(stevenjb): L10N AboutDiscards.
432800a4b202f8b23540dbb128e780ca8b7e90d1f46Eric Anholt
433aea2236af60aee329e6ea73a41f2410d8eacc7b6Chad Versacestd::string AboutDiscardsRun() {
434aea2236af60aee329e6ea73a41f2410d8eacc7b6Chad Versace  std::string output;
435aea2236af60aee329e6ea73a41f2410d8eacc7b6Chad Versace  AppendHeader(&output, 0, "About discards");
436aea2236af60aee329e6ea73a41f2410d8eacc7b6Chad Versace  output.append(
437aea2236af60aee329e6ea73a41f2410d8eacc7b6Chad Versace      base::StringPrintf("<meta http-equiv='refresh' content='2;%s'>",
438aea2236af60aee329e6ea73a41f2410d8eacc7b6Chad Versace      chrome::kChromeUIDiscardsURL));
439aea2236af60aee329e6ea73a41f2410d8eacc7b6Chad Versace  AddContentSecurityPolicy(&output);
440aea2236af60aee329e6ea73a41f2410d8eacc7b6Chad Versace  output.append(WrapWithTag("p", "Discarding a tab..."));
441aea2236af60aee329e6ea73a41f2410d8eacc7b6Chad Versace  g_browser_process->platform_part()->
442aea2236af60aee329e6ea73a41f2410d8eacc7b6Chad Versace      oom_priority_manager()->LogMemoryAndDiscardTab();
443aea2236af60aee329e6ea73a41f2410d8eacc7b6Chad Versace  AppendFooter(&output);
444aea2236af60aee329e6ea73a41f2410d8eacc7b6Chad Versace  return output;
445aea2236af60aee329e6ea73a41f2410d8eacc7b6Chad Versace}
446aea2236af60aee329e6ea73a41f2410d8eacc7b6Chad Versace
447aea2236af60aee329e6ea73a41f2410d8eacc7b6Chad Versacestd::string AboutDiscards(const std::string& path) {
448aea2236af60aee329e6ea73a41f2410d8eacc7b6Chad Versace  std::string output;
449aea2236af60aee329e6ea73a41f2410d8eacc7b6Chad Versace  const char kRunCommand[] = "run";
450aea2236af60aee329e6ea73a41f2410d8eacc7b6Chad Versace  if (path == kRunCommand)
451aea2236af60aee329e6ea73a41f2410d8eacc7b6Chad Versace    return AboutDiscardsRun();
452aea2236af60aee329e6ea73a41f2410d8eacc7b6Chad Versace  AppendHeader(&output, 0, "About discards");
453aea2236af60aee329e6ea73a41f2410d8eacc7b6Chad Versace  AddContentSecurityPolicy(&output);
45477a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt  AppendBody(&output);
45577a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt  output.append("<h3>About discards</h3>");
456f4efb7ff4f9cb0f6386e9b53f4dcfd9ef23dc9d1Chad Versace  output.append(
45777a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt      "<p>Tabs sorted from most interesting to least interesting. The least "
45877a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt      "interesting tab may be discarded if we run out of physical memory.</p>");
4594a253431abf43a0638afb43605b44a8742b72a60Brian Paul
460d282128ff68cc58bc3f5b808031c5fe7325bd69bKristian Høgsberg  chromeos::OomPriorityManager* oom =
46177a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt      g_browser_process->platform_part()->oom_priority_manager();
462f4efb7ff4f9cb0f6386e9b53f4dcfd9ef23dc9d1Chad Versace  std::vector<base::string16> titles = oom->GetTabTitles();
463f4efb7ff4f9cb0f6386e9b53f4dcfd9ef23dc9d1Chad Versace  if (!titles.empty()) {
464f4efb7ff4f9cb0f6386e9b53f4dcfd9ef23dc9d1Chad Versace    output.append("<ul>");
465f4efb7ff4f9cb0f6386e9b53f4dcfd9ef23dc9d1Chad Versace    std::vector<base::string16>::iterator it = titles.begin();
46677a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt    for ( ; it != titles.end(); ++it) {
46777a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt      std::string title = UTF16ToUTF8(*it);
468d282128ff68cc58bc3f5b808031c5fe7325bd69bKristian Høgsberg      title = net::EscapeForHTML(title);
4692e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke      output.append(WrapWithTag("li", title));
4702e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke    }
4712e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke    output.append("</ul>");
472f4efb7ff4f9cb0f6386e9b53f4dcfd9ef23dc9d1Chad Versace  } else {
4732e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke    output.append("<p>None found.  Wait 10 seconds, then refresh.</p>");
4742e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke  }
475d282128ff68cc58bc3f5b808031c5fe7325bd69bKristian Høgsberg  output.append(base::StringPrintf("%d discards this session. ",
47677a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt                             oom->discard_count()));
4772e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke  output.append(base::StringPrintf("<a href='%s%s'>Discard tab now</a>",
47877a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt                                   chrome::kChromeUIDiscardsURL,
47977a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt                                   kRunCommand));
48077a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt
48177a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt  base::SystemMemoryInfoKB meminfo;
482d61f07318c8678901b948fdaa8ccdf37aa3203e9Kristian Høgsberg  base::GetSystemMemoryInfo(&meminfo);
48377a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt  output.append("<h3>System memory information in MB</h3>");
484d282128ff68cc58bc3f5b808031c5fe7325bd69bKristian Høgsberg  output.append("<table>");
485d282128ff68cc58bc3f5b808031c5fe7325bd69bKristian Høgsberg  // Start with summary statistics.
486d282128ff68cc58bc3f5b808031c5fe7325bd69bKristian Høgsberg  output.append(AddStringRow(
48777a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt      "Total", base::IntToString(meminfo.total / 1024)));
48877a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt  output.append(AddStringRow(
48977a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt      "Free", base::IntToString(meminfo.free / 1024)));
49077a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt  int mem_allocated_kb = meminfo.active_anon + meminfo.inactive_anon;
49177a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt#if defined(ARCH_CPU_ARM_FAMILY)
49277a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt  // ARM counts allocated graphics memory separately from anonymous.
4932e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke  if (meminfo.gem_size != -1)
4942e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke    mem_allocated_kb += meminfo.gem_size / 1024;
4952e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke#endif
4962e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke  output.append(AddStringRow(
4972e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke      "Allocated", base::IntToString(mem_allocated_kb / 1024)));
4982e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke  // Add some space, then detailed numbers.
4992e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke  output.append(AddStringRow("&nbsp;", "&nbsp;"));
5002e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke  output.append(AddStringRow(
5012e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke      "Buffered", base::IntToString(meminfo.buffers / 1024)));
5022e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke  output.append(AddStringRow(
5032e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke      "Cached", base::IntToString(meminfo.cached / 1024)));
5042e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke  output.append(AddStringRow(
5052e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke      "Active Anon", base::IntToString(meminfo.active_anon / 1024)));
5062e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke  output.append(AddStringRow(
5072e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke      "Inactive Anon", base::IntToString(meminfo.inactive_anon / 1024)));
50877a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt  output.append(AddStringRow(
50977a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt      "Shared", base::IntToString(meminfo.shmem / 1024)));
510a7a9a91d7b28e5b5faed509d00f0f951e3136b1bKristian Høgsberg  output.append(AddStringRow(
511d3491e775fb07f891463b2185d74bbad62f3ed24Kristian Høgsberg      "Graphics", base::IntToString(meminfo.gem_size / 1024 / 1024)));
512d61f07318c8678901b948fdaa8ccdf37aa3203e9Kristian Høgsberg  output.append("</table>");
51377a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt
51477a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt  AppendFooter(&output);
515d61f07318c8678901b948fdaa8ccdf37aa3203e9Kristian Høgsberg  return output;
5165777dee02c6497207e6b4b9d68de072e7be7c06eKristian Høgsberg}
51777a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt
518bea6b5fe5aa3138cec8d057766ae48da4aa57deeEric Anholt#endif  // OS_CHROMEOS
51919420e6c2592e8a31e2ead4bccebc1a9ccca52b1Eric Anholt
52019420e6c2592e8a31e2ead4bccebc1a9ccca52b1Eric Anholt// AboutDnsHandler bounces the request back to the IO thread to collect
5214b69100bdcf26dbb5be4d600b7ca5f5cdf6e8f20Kristian Høgsberg// the DNS information.
522bea6b5fe5aa3138cec8d057766ae48da4aa57deeEric Anholtclass AboutDnsHandler : public base::RefCountedThreadSafe<AboutDnsHandler> {
52319420e6c2592e8a31e2ead4bccebc1a9ccca52b1Eric Anholt public:
524bea6b5fe5aa3138cec8d057766ae48da4aa57deeEric Anholt  static void Start(Profile* profile,
5252e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke                    const content::URLDataSource::GotDataCallback& callback) {
52677a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt    scoped_refptr<AboutDnsHandler> handler(
52777a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt        new AboutDnsHandler(profile, callback));
528bea6b5fe5aa3138cec8d057766ae48da4aa57deeEric Anholt    handler->StartOnUIThread();
529bea6b5fe5aa3138cec8d057766ae48da4aa57deeEric Anholt  }
5304b69100bdcf26dbb5be4d600b7ca5f5cdf6e8f20Kristian Høgsberg
5314b69100bdcf26dbb5be4d600b7ca5f5cdf6e8f20Kristian Høgsberg private:
532bea6b5fe5aa3138cec8d057766ae48da4aa57deeEric Anholt  friend class base::RefCountedThreadSafe<AboutDnsHandler>;
5334ac2f09e2034d8940a0ce9426a8d5c5d74bc63bdEric Anholt
5342e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke  AboutDnsHandler(Profile* profile,
53577a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt                  const content::URLDataSource::GotDataCallback& callback)
53677a5bcaff43df8d54e0e0ef833726e4b41d7eb36Eric Anholt      : profile_(profile),
5372e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke        callback_(callback) {
5385777dee02c6497207e6b4b9d68de072e7be7c06eKristian Høgsberg    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5397e0bbdcf033981282978554c2e68ce48b55aa291Eric Anholt  }
540d61f07318c8678901b948fdaa8ccdf37aa3203e9Kristian Høgsberg
541cb4ef34214d61fb48bdff689a85ea107060e061bEric Anholt  virtual ~AboutDnsHandler() {}
5427e0bbdcf033981282978554c2e68ce48b55aa291Eric Anholt
5434ac2f09e2034d8940a0ce9426a8d5c5d74bc63bdEric Anholt  // Calls FinishOnUIThread() on completion.
5444ac2f09e2034d8940a0ce9426a8d5c5d74bc63bdEric Anholt  void StartOnUIThread() {
5457e0bbdcf033981282978554c2e68ce48b55aa291Eric Anholt    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
546827ba44f6ee83ab21c6a2b09323f6f1df4a7d4c8Eric Anholt    chrome_browser_net::Predictor* predictor = profile_->GetNetworkPredictor();
5477e0bbdcf033981282978554c2e68ce48b55aa291Eric Anholt    BrowserThread::PostTask(
548827ba44f6ee83ab21c6a2b09323f6f1df4a7d4c8Eric Anholt        BrowserThread::IO, FROM_HERE,
549827ba44f6ee83ab21c6a2b09323f6f1df4a7d4c8Eric Anholt        base::Bind(&AboutDnsHandler::StartOnIOThread, this, predictor));
5502e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke  }
5517e0bbdcf033981282978554c2e68ce48b55aa291Eric Anholt
5527e0bbdcf033981282978554c2e68ce48b55aa291Eric Anholt  void StartOnIOThread(chrome_browser_net::Predictor* predictor) {
553bb35000b4b6dfe60048b2f5d60bc102c4a7fd791Eric Anholt    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
554bb35000b4b6dfe60048b2f5d60bc102c4a7fd791Eric Anholt
555bb35000b4b6dfe60048b2f5d60bc102c4a7fd791Eric Anholt    std::string data;
5562e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke    AppendHeader(&data, 0, "About DNS");
557bb35000b4b6dfe60048b2f5d60bc102c4a7fd791Eric Anholt    AppendBody(&data);
558e7aef006e50d0b859c621267af8376f5a0f43445Eric Anholt    chrome_browser_net::Predictor::PredictorGetHtmlInfo(predictor, &data);
55906d1472ffa0648efa9374fa227894fbf0b0be054Eric Anholt    AppendFooter(&data);
56006d1472ffa0648efa9374fa227894fbf0b0be054Eric Anholt
5612d99588b3556928a0879b4160210ac771dbf1f0bKristian Høgsberg    BrowserThread::PostTask(
5622d99588b3556928a0879b4160210ac771dbf1f0bKristian Høgsberg        BrowserThread::UI, FROM_HERE,
563900a5c91eeb3acae7ee0ad331154531c4dba96e1Chris Wilson        base::Bind(&AboutDnsHandler::FinishOnUIThread, this, data));
564900a5c91eeb3acae7ee0ad331154531c4dba96e1Chris Wilson  }
565900a5c91eeb3acae7ee0ad331154531c4dba96e1Chris Wilson
566900a5c91eeb3acae7ee0ad331154531c4dba96e1Chris Wilson  void FinishOnUIThread(const std::string& data) {
5672e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5687e0bbdcf033981282978554c2e68ce48b55aa291Eric Anholt    std::string data_copy(data);
5697e0bbdcf033981282978554c2e68ce48b55aa291Eric Anholt    callback_.Run(base::RefCountedString::TakeString(&data_copy));
570c5c73c1b605611faf0f06df9b5d08d8984388238Kristian Høgsberg  }
5716b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace
5726b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace  Profile* profile_;
5736b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace
5746b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace  // Callback to run with the response.
5756b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace  content::URLDataSource::GotDataCallback callback_;
5766b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace
5776b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace  DISALLOW_COPY_AND_ASSIGN(AboutDnsHandler);
5786b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace};
5796b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace
5806b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versacevoid FinishMemoryDataRequest(
5816b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace    const std::string& path,
5826b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace    const content::URLDataSource::GotDataCallback& callback) {
5836b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace  if (path == kStringsJsPath) {
5846b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace    // The AboutMemoryHandler cleans itself up, but |StartFetch()| will want
5856b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace    // the refcount to be greater than 0.
5866b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace    scoped_refptr<AboutMemoryHandler> handler(new AboutMemoryHandler(callback));
5876b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace    // TODO(jamescook): Maybe this shouldn't update UMA?
5886b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace    handler->StartFetch(MemoryDetails::UPDATE_USER_METRICS);
5896b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace  } else {
5906b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace    int id = IDR_ABOUT_MEMORY_HTML;
5916b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace    if (path == kMemoryJsPath) {
5926b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace      id = IDR_ABOUT_MEMORY_JS;
5936b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace    } else if (path == kMemoryCssPath) {
5946b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace      id = IDR_ABOUT_MEMORY_CSS;
5956b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace    }
5966b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace
5976b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace    std::string result =
5986b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace        ResourceBundle::GetSharedInstance().GetRawDataResource(id).as_string();
5996b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace    callback.Run(base::RefCountedString::TakeString(&result));
6006b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace  }
6016b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace}
6026b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace
6036b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace// Handler for filling in the "about:stats" page, as called by the browser's
6046b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace// About handler processing.
6056b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace// |query| is roughly the query string of the about:stats URL.
6066b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace// Returns a string containing the HTML to render for the about:stats page.
6076b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace// Conditional Output:
6086b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace//      if |query| is "json", returns a JSON format of all counters.
6096b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace//      if |query| is "raw", returns plain text of counter deltas.
6106b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace//      otherwise, returns HTML with pretty JS/HTML to display the data.
6116b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versacestd::string AboutStats(const std::string& query) {
6126b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace  // We keep the DictionaryValue tree live so that we can do delta
6136b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace  // stats computations across runs.
6146b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace  CR_DEFINE_STATIC_LOCAL(DictionaryValue, root, ());
6156b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace  static base::TimeTicks last_sample_time = base::TimeTicks::Now();
6166b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace
6176b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace  base::TimeTicks now = base::TimeTicks::Now();
6186b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace  base::TimeDelta time_since_last_sample = now - last_sample_time;
619c5c73c1b605611faf0f06df9b5d08d8984388238Kristian Høgsberg  last_sample_time = now;
6208d976aedc4654bc66b80f22690e3674f1ef46183Brian Paul
6218d976aedc4654bc66b80f22690e3674f1ef46183Brian Paul  base::StatsTable* table = base::StatsTable::current();
622d3491e775fb07f891463b2185d74bbad62f3ed24Kristian Høgsberg  if (!table)
623c5c73c1b605611faf0f06df9b5d08d8984388238Kristian Høgsberg    return std::string();
624e82dd8c6e1fa2fff5b960de26961080ba5e9651dKristian Høgsberg
625d61f07318c8678901b948fdaa8ccdf37aa3203e9Kristian Høgsberg  // We maintain two lists - one for counters and one for timers.
626c5c73c1b605611faf0f06df9b5d08d8984388238Kristian Høgsberg  // Timers actually get stored on both lists.
6275777dee02c6497207e6b4b9d68de072e7be7c06eKristian Høgsberg  ListValue* counters;
6283ee21f30cda27e0ee1357f930163526622ba9434Eric Anholt  if (!root.GetList("counters", &counters)) {
6293ee21f30cda27e0ee1357f930163526622ba9434Eric Anholt    counters = new ListValue();
6305efee4d4e68067a3fd85b9ff6a2636f502538768Kristian Høgsberg    root.Set("counters", counters);
6314ac2f09e2034d8940a0ce9426a8d5c5d74bc63bdEric Anholt  }
6327c50d29f7ced3d60e52ee0146d982b49ea421de2Kristian Høgsberg
6333ee21f30cda27e0ee1357f930163526622ba9434Eric Anholt  ListValue* timers;
6346bd9da01eacf9d100dfb0a9529700aa894a23d24Ian Romanick  if (!root.GetList("timers", &timers)) {
6353ee21f30cda27e0ee1357f930163526622ba9434Eric Anholt    timers = new ListValue();
636e13593678f62941db06b7ae1a21b81c643371659Brian Paul    root.Set("timers", timers);
6373ee21f30cda27e0ee1357f930163526622ba9434Eric Anholt  }
6385d5ae371eaeca7e33e638af3aee1ae8e162db0a7Eric Anholt
639c5c73c1b605611faf0f06df9b5d08d8984388238Kristian Høgsberg  // NOTE: Counters start at index 1.
640c5c73c1b605611faf0f06df9b5d08d8984388238Kristian Høgsberg  for (int index = 1; index <= table->GetMaxCounters(); index++) {
6415777dee02c6497207e6b4b9d68de072e7be7c06eKristian Høgsberg    // Get the counter's full name
642c5c73c1b605611faf0f06df9b5d08d8984388238Kristian Høgsberg    std::string full_name = table->GetRowName(index);
643c5c73c1b605611faf0f06df9b5d08d8984388238Kristian Høgsberg    if (full_name.length() == 0)
6442e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke      break;
645c5c73c1b605611faf0f06df9b5d08d8984388238Kristian Høgsberg    DCHECK_EQ(':', full_name[1]);
646c5c73c1b605611faf0f06df9b5d08d8984388238Kristian Høgsberg    char counter_type = full_name[0];
647c5c73c1b605611faf0f06df9b5d08d8984388238Kristian Høgsberg    std::string name = full_name.substr(2);
648c5c73c1b605611faf0f06df9b5d08d8984388238Kristian Høgsberg
649c5c73c1b605611faf0f06df9b5d08d8984388238Kristian Høgsberg    // JSON doesn't allow '.' in names.
650c5c73c1b605611faf0f06df9b5d08d8984388238Kristian Høgsberg    size_t pos;
651c5c73c1b605611faf0f06df9b5d08d8984388238Kristian Høgsberg    while ((pos = name.find(".")) != std::string::npos)
652c5c73c1b605611faf0f06df9b5d08d8984388238Kristian Høgsberg      name.replace(pos, 1, ":");
653f56b569e9af356c11869ee49a4669bb01b75397eKristian Høgsberg
654c5c73c1b605611faf0f06df9b5d08d8984388238Kristian Høgsberg    // Try to see if this name already exists.
655c5c73c1b605611faf0f06df9b5d08d8984388238Kristian Høgsberg    DictionaryValue* counter = NULL;
6562e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke    for (size_t scan_index = 0;
657c5c73c1b605611faf0f06df9b5d08d8984388238Kristian Høgsberg         scan_index < counters->GetSize(); scan_index++) {
6584ac2f09e2034d8940a0ce9426a8d5c5d74bc63bdEric Anholt      DictionaryValue* dictionary;
6594ac2f09e2034d8940a0ce9426a8d5c5d74bc63bdEric Anholt      if (counters->GetDictionary(scan_index, &dictionary)) {
6604ac2f09e2034d8940a0ce9426a8d5c5d74bc63bdEric Anholt        std::string scan_name;
6614ac2f09e2034d8940a0ce9426a8d5c5d74bc63bdEric Anholt        if (dictionary->GetString("name", &scan_name) && scan_name == name) {
6624ac2f09e2034d8940a0ce9426a8d5c5d74bc63bdEric Anholt          counter = dictionary;
6634ac2f09e2034d8940a0ce9426a8d5c5d74bc63bdEric Anholt        }
6644ac2f09e2034d8940a0ce9426a8d5c5d74bc63bdEric Anholt      } else {
6654ac2f09e2034d8940a0ce9426a8d5c5d74bc63bdEric Anholt        NOTREACHED();  // Should always be there
6664ac2f09e2034d8940a0ce9426a8d5c5d74bc63bdEric Anholt      }
6674ac2f09e2034d8940a0ce9426a8d5c5d74bc63bdEric Anholt    }
66889a82d72cafc1efbcf099e5229ba9b1cb53504f0Kenneth Graunke
66989a82d72cafc1efbcf099e5229ba9b1cb53504f0Kenneth Graunke    if (counter == NULL) {
67089a82d72cafc1efbcf099e5229ba9b1cb53504f0Kenneth Graunke      counter = new DictionaryValue();
6717363088f9f9558b2bad3ac6da48947514a8cd790Kristian Høgsberg      counter->SetString("name", name);
6727363088f9f9558b2bad3ac6da48947514a8cd790Kristian Høgsberg      counters->Append(counter);
6737363088f9f9558b2bad3ac6da48947514a8cd790Kristian Høgsberg    }
6747363088f9f9558b2bad3ac6da48947514a8cd790Kristian Høgsberg
6757363088f9f9558b2bad3ac6da48947514a8cd790Kristian Høgsberg    switch (counter_type) {
6767363088f9f9558b2bad3ac6da48947514a8cd790Kristian Høgsberg      case 'c':
6777363088f9f9558b2bad3ac6da48947514a8cd790Kristian Høgsberg        {
6787363088f9f9558b2bad3ac6da48947514a8cd790Kristian Høgsberg          int new_value = table->GetRowValue(index);
6797363088f9f9558b2bad3ac6da48947514a8cd790Kristian Høgsberg          int prior_value = 0;
6807363088f9f9558b2bad3ac6da48947514a8cd790Kristian Høgsberg          int delta = 0;
6817363088f9f9558b2bad3ac6da48947514a8cd790Kristian Høgsberg          if (counter->GetInteger("value", &prior_value)) {
6826b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace            delta = new_value - prior_value;
6836b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace          }
6846b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace          counter->SetInteger("value", new_value);
6856b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace          counter->SetInteger("delta", delta);
6866b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace        }
6876b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace        break;
6886b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace      case 'm':
6896b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace        {
6906b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace          // TODO(mbelshe): implement me.
6916b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace        }
6926b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace        break;
6936b2bf272ee173bd8ee6c731500861de21fa01b5fChad Versace      case 't':
6945efee4d4e68067a3fd85b9ff6a2636f502538768Kristian Høgsberg        {
6955efee4d4e68067a3fd85b9ff6a2636f502538768Kristian Høgsberg          int time = table->GetRowValue(index);
6965efee4d4e68067a3fd85b9ff6a2636f502538768Kristian Høgsberg          counter->SetInteger("time", time);
6975efee4d4e68067a3fd85b9ff6a2636f502538768Kristian Høgsberg
6985efee4d4e68067a3fd85b9ff6a2636f502538768Kristian Høgsberg          // Store this on the timers list as well.
6995efee4d4e68067a3fd85b9ff6a2636f502538768Kristian Høgsberg          timers->Append(counter);
7005efee4d4e68067a3fd85b9ff6a2636f502538768Kristian Høgsberg        }
7015efee4d4e68067a3fd85b9ff6a2636f502538768Kristian Høgsberg        break;
7025efee4d4e68067a3fd85b9ff6a2636f502538768Kristian Høgsberg      default:
7035efee4d4e68067a3fd85b9ff6a2636f502538768Kristian Høgsberg        NOTREACHED();
7045efee4d4e68067a3fd85b9ff6a2636f502538768Kristian Høgsberg    }
7057e0bbdcf033981282978554c2e68ce48b55aa291Eric Anholt  }
7062e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke
7077e0bbdcf033981282978554c2e68ce48b55aa291Eric Anholt  std::string data;
708e82dd8c6e1fa2fff5b960de26961080ba5e9651dKristian Høgsberg  if (query == "json" || query == kStringsJsPath) {
709c5c73c1b605611faf0f06df9b5d08d8984388238Kristian Høgsberg    base::JSONWriter::WriteWithOptions(
710eaf15db895e3a5c6c5ccc2f23a4f0fa522855868Michel Dänzer          &root,
711eaf15db895e3a5c6c5ccc2f23a4f0fa522855868Michel Dänzer          base::JSONWriter::OPTIONS_PRETTY_PRINT,
7123ee21f30cda27e0ee1357f930163526622ba9434Eric Anholt          &data);
7133ee21f30cda27e0ee1357f930163526622ba9434Eric Anholt    if (query == kStringsJsPath)
7143ee21f30cda27e0ee1357f930163526622ba9434Eric Anholt      data = "var templateData = " + data + ";";
71524ff169486e315671c09cd8a57a311a935ccfff5Eric Anholt  } else if (query == "raw") {
7163ee21f30cda27e0ee1357f930163526622ba9434Eric Anholt    // Dump the raw counters which have changed in text format.
7173ee21f30cda27e0ee1357f930163526622ba9434Eric Anholt    data = "<pre>";
71824ff169486e315671c09cd8a57a311a935ccfff5Eric Anholt    data.append(base::StringPrintf("Counter changes in the last %ldms\n",
7193ee21f30cda27e0ee1357f930163526622ba9434Eric Anholt        static_cast<long int>(time_since_last_sample.InMilliseconds())));
7203ee21f30cda27e0ee1357f930163526622ba9434Eric Anholt    for (size_t i = 0; i < counters->GetSize(); ++i) {
721160c3617fc8867edc445b1ba62fc996c4630cc35Eric Anholt      Value* entry = NULL;
722160c3617fc8867edc445b1ba62fc996c4630cc35Eric Anholt      bool rv = counters->Get(i, &entry);
723160c3617fc8867edc445b1ba62fc996c4630cc35Eric Anholt      if (!rv)
724bb65a1d009e3d8398492aa30d944c17a40535aa1Ian Romanick        continue;  // None of these should fail.
725bb65a1d009e3d8398492aa30d944c17a40535aa1Ian Romanick      DictionaryValue* counter = static_cast<DictionaryValue*>(entry);
726bb65a1d009e3d8398492aa30d944c17a40535aa1Ian Romanick      int delta;
7273ee21f30cda27e0ee1357f930163526622ba9434Eric Anholt      rv = counter->GetInteger("delta", &delta);
7285d5ae371eaeca7e33e638af3aee1ae8e162db0a7Eric Anholt      if (!rv)
729160c3617fc8867edc445b1ba62fc996c4630cc35Eric Anholt        continue;
730160c3617fc8867edc445b1ba62fc996c4630cc35Eric Anholt      if (delta > 0) {
731066f45c7a1888ca8a9de78a81b38af7c74bca9e1Ian Romanick        std::string name;
732066f45c7a1888ca8a9de78a81b38af7c74bca9e1Ian Romanick        rv = counter->GetString("name", &name);
733066f45c7a1888ca8a9de78a81b38af7c74bca9e1Ian Romanick        if (!rv)
734160c3617fc8867edc445b1ba62fc996c4630cc35Eric Anholt          continue;
735160c3617fc8867edc445b1ba62fc996c4630cc35Eric Anholt        int value;
736160c3617fc8867edc445b1ba62fc996c4630cc35Eric Anholt        rv = counter->GetInteger("value", &value);
737160c3617fc8867edc445b1ba62fc996c4630cc35Eric Anholt        if (!rv)
738160c3617fc8867edc445b1ba62fc996c4630cc35Eric Anholt          continue;
739160c3617fc8867edc445b1ba62fc996c4630cc35Eric Anholt        data.append(name);
74073e24cd5a7a0760726a681dda5b88805ddcf1555Ian Romanick        data.append(":");
741160c3617fc8867edc445b1ba62fc996c4630cc35Eric Anholt        data.append(base::IntToString(delta));
74273e24cd5a7a0760726a681dda5b88805ddcf1555Ian Romanick        data.append("\n");
74373e24cd5a7a0760726a681dda5b88805ddcf1555Ian Romanick      }
74473e24cd5a7a0760726a681dda5b88805ddcf1555Ian Romanick    }
7455d5ae371eaeca7e33e638af3aee1ae8e162db0a7Eric Anholt    data.append("</pre>");
7465d5ae371eaeca7e33e638af3aee1ae8e162db0a7Eric Anholt  } else {
7475d5ae371eaeca7e33e638af3aee1ae8e162db0a7Eric Anholt    // Get about_stats.html/js from resource bundle.
748160c3617fc8867edc445b1ba62fc996c4630cc35Eric Anholt    data = ResourceBundle::GetSharedInstance().GetRawDataResource(
7495d5ae371eaeca7e33e638af3aee1ae8e162db0a7Eric Anholt        (query == kStatsJsPath ?
7505d5ae371eaeca7e33e638af3aee1ae8e162db0a7Eric Anholt         IDR_ABOUT_STATS_JS : IDR_ABOUT_STATS_HTML)).as_string();
7515d5ae371eaeca7e33e638af3aee1ae8e162db0a7Eric Anholt
7523cce4a1e10361458630511543b7a8a6438544775Ian Romanick    if (query != kStatsJsPath) {
7532e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke      // Clear the timer list since we stored the data in the timers list
754bb65a1d009e3d8398492aa30d944c17a40535aa1Ian Romanick      // as well.
755bb65a1d009e3d8398492aa30d944c17a40535aa1Ian Romanick      for (int index = static_cast<int>(timers->GetSize())-1; index >= 0;
756bb65a1d009e3d8398492aa30d944c17a40535aa1Ian Romanick           index--) {
757bb65a1d009e3d8398492aa30d944c17a40535aa1Ian Romanick        scoped_ptr<Value> value;
758bb65a1d009e3d8398492aa30d944c17a40535aa1Ian Romanick        timers->Remove(index, &value);
759bb65a1d009e3d8398492aa30d944c17a40535aa1Ian Romanick        // We don't care about the value pointer; it's still tracked
760bb65a1d009e3d8398492aa30d944c17a40535aa1Ian Romanick        // on the counters list.
761bb65a1d009e3d8398492aa30d944c17a40535aa1Ian Romanick        ignore_result(value.release());
762bb65a1d009e3d8398492aa30d944c17a40535aa1Ian Romanick      }
763bb65a1d009e3d8398492aa30d944c17a40535aa1Ian Romanick    }
764bb65a1d009e3d8398492aa30d944c17a40535aa1Ian Romanick  }
765bb65a1d009e3d8398492aa30d944c17a40535aa1Ian Romanick
766bb65a1d009e3d8398492aa30d944c17a40535aa1Ian Romanick  return data;
767bb65a1d009e3d8398492aa30d944c17a40535aa1Ian Romanick}
768bb65a1d009e3d8398492aa30d944c17a40535aa1Ian Romanick
769bb65a1d009e3d8398492aa30d944c17a40535aa1Ian Romanick#if defined(OS_LINUX) || defined(OS_OPENBSD)
770bb65a1d009e3d8398492aa30d944c17a40535aa1Ian Romanickstd::string AboutLinuxProxyConfig() {
771bb65a1d009e3d8398492aa30d944c17a40535aa1Ian Romanick  std::string data;
772bb65a1d009e3d8398492aa30d944c17a40535aa1Ian Romanick  AppendHeader(&data, 0,
773bb65a1d009e3d8398492aa30d944c17a40535aa1Ian Romanick               l10n_util::GetStringUTF8(IDS_ABOUT_LINUX_PROXY_CONFIG_TITLE));
774bb65a1d009e3d8398492aa30d944c17a40535aa1Ian Romanick  data.append("<style>body { max-width: 70ex; padding: 2ex 5ex; }</style>");
775bb65a1d009e3d8398492aa30d944c17a40535aa1Ian Romanick  AppendBody(&data);
776bb65a1d009e3d8398492aa30d944c17a40535aa1Ian Romanick  base::FilePath binary = CommandLine::ForCurrentProcess()->GetProgram();
777bb65a1d009e3d8398492aa30d944c17a40535aa1Ian Romanick  data.append(l10n_util::GetStringFUTF8(
7782e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke      IDS_ABOUT_LINUX_PROXY_CONFIG_BODY,
7793ee21f30cda27e0ee1357f930163526622ba9434Eric Anholt      l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
7803ee21f30cda27e0ee1357f930163526622ba9434Eric Anholt      ASCIIToUTF16(binary.BaseName().value())));
7813ee21f30cda27e0ee1357f930163526622ba9434Eric Anholt  AppendFooter(&data);
7823ee21f30cda27e0ee1357f930163526622ba9434Eric Anholt  return data;
7833ee21f30cda27e0ee1357f930163526622ba9434Eric Anholt}
7843ee21f30cda27e0ee1357f930163526622ba9434Eric Anholt
7853ee21f30cda27e0ee1357f930163526622ba9434Eric Anholtvoid AboutSandboxRow(std::string* data, const std::string& prefix, int name_id,
7863ee21f30cda27e0ee1357f930163526622ba9434Eric Anholt                     bool good) {
7873ee21f30cda27e0ee1357f930163526622ba9434Eric Anholt  data->append("<tr><td>");
7883ee21f30cda27e0ee1357f930163526622ba9434Eric Anholt  data->append(prefix);
7893ee21f30cda27e0ee1357f930163526622ba9434Eric Anholt  data->append(l10n_util::GetStringUTF8(name_id));
7903ee21f30cda27e0ee1357f930163526622ba9434Eric Anholt  if (good) {
7915d5ae371eaeca7e33e638af3aee1ae8e162db0a7Eric Anholt    data->append("</td><td style='color: green;'>");
792c5c73c1b605611faf0f06df9b5d08d8984388238Kristian Høgsberg    data->append(
793e82dd8c6e1fa2fff5b960de26961080ba5e9651dKristian Høgsberg        l10n_util::GetStringUTF8(IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL));
7942adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke  } else {
7952adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke    data->append("</td><td style='color: red;'>");
7962adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke    data->append(
7972adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke        l10n_util::GetStringUTF8(IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL));
7982adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke  }
7992adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke  data->append("</td></tr>");
8002adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke}
8012adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke
8022adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzkestd::string AboutSandbox() {
8032adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke  std::string data;
8042adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke  AppendHeader(&data, 0, l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_TITLE));
8052adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke  AppendBody(&data);
8065dfba09d49ccec2655e4d22ef6f46b9c67862bc9Kristian Høgsberg  data.append("<h1>");
8072adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke  data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_TITLE));
8082adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke  data.append("</h1>");
8092adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke
8102adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke  // Get expected sandboxing status of renderers.
8112adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke  const int status = content::ZygoteHost::GetInstance()->GetSandboxStatus();
8125dfba09d49ccec2655e4d22ef6f46b9c67862bc9Kristian Høgsberg
8135dfba09d49ccec2655e4d22ef6f46b9c67862bc9Kristian Høgsberg  data.append("<table>");
8145dfba09d49ccec2655e4d22ef6f46b9c67862bc9Kristian Høgsberg
8155dfba09d49ccec2655e4d22ef6f46b9c67862bc9Kristian Høgsberg  AboutSandboxRow(&data,
8165dfba09d49ccec2655e4d22ef6f46b9c67862bc9Kristian Høgsberg                  std::string(),
8175dfba09d49ccec2655e4d22ef6f46b9c67862bc9Kristian Høgsberg                  IDS_ABOUT_SANDBOX_SUID_SANDBOX,
8185dfba09d49ccec2655e4d22ef6f46b9c67862bc9Kristian Høgsberg                  status & content::kSandboxLinuxSUID);
8195dfba09d49ccec2655e4d22ef6f46b9c67862bc9Kristian Høgsberg  AboutSandboxRow(&data, "&nbsp;&nbsp;", IDS_ABOUT_SANDBOX_PID_NAMESPACES,
8205dfba09d49ccec2655e4d22ef6f46b9c67862bc9Kristian Høgsberg                  status & content::kSandboxLinuxPIDNS);
8212e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke  AboutSandboxRow(&data, "&nbsp;&nbsp;", IDS_ABOUT_SANDBOX_NET_NAMESPACES,
8222adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke                  status & content::kSandboxLinuxNetNS);
8232adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke  AboutSandboxRow(&data,
8242adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke                  std::string(),
8252adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke                  IDS_ABOUT_SANDBOX_SECCOMP_BPF_SANDBOX,
8262adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke                  status & content::kSandboxLinuxSeccompBPF);
8272adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke
8282adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke  data.append("</table>");
8292adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke
8302adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke  // The setuid sandbox is required as our first-layer sandbox.
8312adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke  bool good_layer1 = status & content::kSandboxLinuxSUID &&
8322adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke                     status & content::kSandboxLinuxPIDNS &&
8332adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke                     status & content::kSandboxLinuxNetNS;
8342adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke  // A second-layer sandbox is also required to be adequately sandboxed.
8352adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke  bool good_layer2 = status & content::kSandboxLinuxSeccompBPF;
8362adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke  bool good = good_layer1 && good_layer2;
8372adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke
8382adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke  if (good) {
8392adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke    data.append("<p style='color: green'>");
8402adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke    data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_OK));
8412adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke  } else {
8422adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke    data.append("<p style='color: red'>");
8432adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke    data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_BAD));
8442adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke  }
8452adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke  data.append("</p>");
8462adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke
8472adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke  AppendFooter(&data);
848e82dd8c6e1fa2fff5b960de26961080ba5e9651dKristian Høgsberg  return data;
8497192c37294964b3f6e1551469f161593ec8f851dGeorge Sapountzis}
850e82dd8c6e1fa2fff5b960de26961080ba5e9651dKristian Høgsberg#endif
851e82dd8c6e1fa2fff5b960de26961080ba5e9651dKristian Høgsberg
852e82dd8c6e1fa2fff5b960de26961080ba5e9651dKristian Høgsberg// AboutMemoryHandler ----------------------------------------------------------
853e82dd8c6e1fa2fff5b960de26961080ba5e9651dKristian Høgsberg
854e82dd8c6e1fa2fff5b960de26961080ba5e9651dKristian Høgsberg// Helper for AboutMemory to bind results from a ProcessMetrics object
855e82dd8c6e1fa2fff5b960de26961080ba5e9651dKristian Høgsberg// to a DictionaryValue. Fills ws_usage and comm_usage so that the objects
856e82dd8c6e1fa2fff5b960de26961080ba5e9651dKristian Høgsberg// can be used in caller's scope (e.g for appending to a net total).
8572adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzkevoid AboutMemoryHandler::BindProcessMetrics(DictionaryValue* data,
8582adfde3aaee43d7ec974d25794a07fe02f36c6cdBenjamin Franzke                                            ProcessMemoryInformation* info) {
859e82dd8c6e1fa2fff5b960de26961080ba5e9651dKristian Høgsberg  DCHECK(data && info);
86039a0e4e7de379a182c1544fa24d5cb2a7687ec72Kristian Høgsberg
86139a0e4e7de379a182c1544fa24d5cb2a7687ec72Kristian Høgsberg  // Bind metrics to dictionary.
86239a0e4e7de379a182c1544fa24d5cb2a7687ec72Kristian Høgsberg  data->SetInteger("ws_priv", static_cast<int>(info->working_set.priv));
86339a0e4e7de379a182c1544fa24d5cb2a7687ec72Kristian Høgsberg  data->SetInteger("ws_shareable",
86439a0e4e7de379a182c1544fa24d5cb2a7687ec72Kristian Høgsberg    static_cast<int>(info->working_set.shareable));
86539a0e4e7de379a182c1544fa24d5cb2a7687ec72Kristian Høgsberg  data->SetInteger("ws_shared", static_cast<int>(info->working_set.shared));
86639a0e4e7de379a182c1544fa24d5cb2a7687ec72Kristian Høgsberg  data->SetInteger("comm_priv", static_cast<int>(info->committed.priv));
867  data->SetInteger("comm_map", static_cast<int>(info->committed.mapped));
868  data->SetInteger("comm_image", static_cast<int>(info->committed.image));
869  data->SetInteger("pid", info->pid);
870  data->SetString("version", info->version);
871  data->SetInteger("processes", info->num_processes);
872}
873
874// Helper for AboutMemory to append memory usage information for all
875// sub-processes (i.e. renderers, plugins) used by Chrome.
876void AboutMemoryHandler::AppendProcess(ListValue* child_data,
877                                       ProcessMemoryInformation* info) {
878  DCHECK(child_data && info);
879
880  // Append a new DictionaryValue for this renderer to our list.
881  DictionaryValue* child = new DictionaryValue();
882  child_data->Append(child);
883  BindProcessMetrics(child, info);
884
885  std::string child_label(
886      ProcessMemoryInformation::GetFullTypeNameInEnglish(info->process_type,
887                                                         info->renderer_type));
888  if (info->is_diagnostics)
889    child_label.append(" (diagnostics)");
890  child->SetString("child_name", child_label);
891  ListValue* titles = new ListValue();
892  child->Set("titles", titles);
893  for (size_t i = 0; i < info->titles.size(); ++i)
894    titles->Append(new StringValue(info->titles[i]));
895}
896
897void AboutMemoryHandler::OnDetailsAvailable() {
898  // the root of the JSON hierarchy for about:memory jstemplate
899  scoped_ptr<DictionaryValue> root(new DictionaryValue);
900  ListValue* browsers = new ListValue();
901  root->Set("browsers", browsers);
902
903  const std::vector<ProcessData>& browser_processes = processes();
904
905  // Aggregate per-process data into browser summary data.
906  base::string16 log_string;
907  for (size_t index = 0; index < browser_processes.size(); index++) {
908    if (browser_processes[index].processes.empty())
909      continue;
910
911    // Sum the information for the processes within this browser.
912    ProcessMemoryInformation aggregate;
913    ProcessMemoryInformationList::const_iterator iterator;
914    iterator = browser_processes[index].processes.begin();
915    aggregate.pid = iterator->pid;
916    aggregate.version = iterator->version;
917    while (iterator != browser_processes[index].processes.end()) {
918      if (!iterator->is_diagnostics ||
919          browser_processes[index].processes.size() == 1) {
920        aggregate.working_set.priv += iterator->working_set.priv;
921        aggregate.working_set.shared += iterator->working_set.shared;
922        aggregate.working_set.shareable += iterator->working_set.shareable;
923        aggregate.committed.priv += iterator->committed.priv;
924        aggregate.committed.mapped += iterator->committed.mapped;
925        aggregate.committed.image += iterator->committed.image;
926        aggregate.num_processes++;
927      }
928      ++iterator;
929    }
930    DictionaryValue* browser_data = new DictionaryValue();
931    browsers->Append(browser_data);
932    browser_data->SetString("name", browser_processes[index].name);
933
934    BindProcessMetrics(browser_data, &aggregate);
935
936    // We log memory info as we record it.
937    if (!log_string.empty())
938      log_string += ASCIIToUTF16(", ");
939    log_string += browser_processes[index].name + ASCIIToUTF16(", ") +
940                  base::Int64ToString16(aggregate.working_set.priv) +
941                  ASCIIToUTF16(", ") +
942                  base::Int64ToString16(aggregate.working_set.shared) +
943                  ASCIIToUTF16(", ") +
944                  base::Int64ToString16(aggregate.working_set.shareable);
945  }
946  if (!log_string.empty())
947    VLOG(1) << "memory: " << log_string;
948
949  // Set the browser & renderer detailed process data.
950  DictionaryValue* browser_data = new DictionaryValue();
951  root->Set("browzr_data", browser_data);
952  ListValue* child_data = new ListValue();
953  root->Set("child_data", child_data);
954
955  ProcessData process = browser_processes[0];  // Chrome is the first browser.
956  root->SetString("current_browser_name", process.name);
957
958  for (size_t index = 0; index < process.processes.size(); index++) {
959    if (process.processes[index].process_type == content::PROCESS_TYPE_BROWSER)
960      BindProcessMetrics(browser_data, &process.processes[index]);
961    else
962      AppendProcess(child_data, &process.processes[index]);
963  }
964
965  root->SetBoolean("show_other_browsers",
966      browser_defaults::kShowOtherBrowsersInAboutMemory);
967
968  DictionaryValue load_time_data;
969  load_time_data.SetString(
970      "summary_desc",
971      l10n_util::GetStringUTF16(IDS_MEMORY_USAGE_SUMMARY_DESC));
972  webui::SetFontAndTextDirection(&load_time_data);
973  load_time_data.Set("jstemplateData", root.release());
974
975  webui::UseVersion2 version2;
976  std::string data;
977  webui::AppendJsonJS(&load_time_data, &data);
978  callback_.Run(base::RefCountedString::TakeString(&data));
979}
980
981}  // namespace
982
983// AboutUIHTMLSource ----------------------------------------------------------
984
985AboutUIHTMLSource::AboutUIHTMLSource(const std::string& source_name,
986                                     Profile* profile)
987    : source_name_(source_name),
988      profile_(profile) {}
989
990AboutUIHTMLSource::~AboutUIHTMLSource() {}
991
992std::string AboutUIHTMLSource::GetSource() const {
993  return source_name_;
994}
995
996void AboutUIHTMLSource::StartDataRequest(
997    const std::string& path,
998    int render_process_id,
999    int render_view_id,
1000    const content::URLDataSource::GotDataCallback& callback) {
1001  std::string response;
1002  // Add your data source here, in alphabetical order.
1003  if (source_name_ == chrome::kChromeUIChromeURLsHost) {
1004    response = ChromeURLs();
1005  } else if (source_name_ == chrome::kChromeUICreditsHost) {
1006    int idr = (path == kCreditsJsPath) ? IDR_CREDITS_JS : IDR_CREDITS_HTML;
1007    response = ResourceBundle::GetSharedInstance().GetRawDataResource(
1008        idr).as_string();
1009#if defined(OS_CHROMEOS)
1010  } else if (source_name_ == chrome::kChromeUIDiscardsHost) {
1011    response = AboutDiscards(path);
1012#endif
1013  } else if (source_name_ == chrome::kChromeUIDNSHost) {
1014    AboutDnsHandler::Start(profile(), callback);
1015    return;
1016#if defined(OS_LINUX) || defined(OS_OPENBSD)
1017  } else if (source_name_ == chrome::kChromeUILinuxProxyConfigHost) {
1018    response = AboutLinuxProxyConfig();
1019#endif
1020  } else if (source_name_ == chrome::kChromeUIMemoryHost) {
1021    response = GetAboutMemoryRedirectResponse(profile());
1022  } else if (source_name_ == chrome::kChromeUIMemoryRedirectHost) {
1023    FinishMemoryDataRequest(path, callback);
1024    return;
1025#if defined(OS_CHROMEOS)
1026  } else if (source_name_ == chrome::kChromeUIOSCreditsHost) {
1027    response = ResourceBundle::GetSharedInstance().GetRawDataResource(
1028        IDR_OS_CREDITS_HTML).as_string();
1029#endif
1030#if defined(OS_LINUX) || defined(OS_OPENBSD)
1031  } else if (source_name_ == chrome::kChromeUISandboxHost) {
1032    response = AboutSandbox();
1033#endif
1034  } else if (source_name_ == chrome::kChromeUIStatsHost) {
1035    response = AboutStats(path);
1036  } else if (source_name_ == chrome::kChromeUITermsHost) {
1037#if defined(OS_CHROMEOS)
1038    ChromeOSTermsHandler::Start(path, callback);
1039    return;
1040#else
1041    response = l10n_util::GetStringUTF8(IDS_TERMS_HTML);
1042#endif
1043  }
1044
1045  FinishDataRequest(response, callback);
1046}
1047
1048void AboutUIHTMLSource::FinishDataRequest(
1049    const std::string& html,
1050    const content::URLDataSource::GotDataCallback& callback) {
1051  std::string html_copy(html);
1052  callback.Run(base::RefCountedString::TakeString(&html_copy));
1053}
1054
1055std::string AboutUIHTMLSource::GetMimeType(const std::string& path) const {
1056  if (path == kCreditsJsPath ||
1057      path == kStatsJsPath   ||
1058      path == kStringsJsPath ||
1059      path == kMemoryJsPath) {
1060    return "application/javascript";
1061  }
1062  return "text/html";
1063}
1064
1065bool AboutUIHTMLSource::ShouldAddContentSecurityPolicy() const {
1066#if defined(OS_CHROMEOS)
1067  if (source_name_ == chrome::kChromeUIOSCreditsHost)
1068    return false;
1069#endif
1070  return content::URLDataSource::ShouldAddContentSecurityPolicy();
1071}
1072
1073bool AboutUIHTMLSource::ShouldDenyXFrameOptions() const {
1074#if defined(OS_CHROMEOS)
1075  if (source_name_ == chrome::kChromeUITermsHost) {
1076    // chrome://terms page is embedded in iframe to chrome://oobe.
1077    return false;
1078  }
1079#endif
1080  return content::URLDataSource::ShouldDenyXFrameOptions();
1081}
1082
1083AboutUI::AboutUI(content::WebUI* web_ui, const std::string& name)
1084    : WebUIController(web_ui) {
1085  Profile* profile = Profile::FromWebUI(web_ui);
1086
1087#if defined(ENABLE_THEMES)
1088  // Set up the chrome://theme/ source.
1089  ThemeSource* theme = new ThemeSource(profile);
1090  content::URLDataSource::Add(profile, theme);
1091#endif
1092
1093  content::URLDataSource::Add(profile, new AboutUIHTMLSource(name, profile));
1094}
1095