1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/browser_about_handler.h" 6 7 #include <algorithm> 8 #include <string> 9 #include <vector> 10 11 #include "base/callback.h" 12 #include "base/command_line.h" 13 #include "base/file_util.h" 14 #include "base/i18n/number_formatting.h" 15 #include "base/json/json_writer.h" 16 #include "base/memory/singleton.h" 17 #include "base/metrics/histogram.h" 18 #include "base/metrics/stats_table.h" 19 #include "base/path_service.h" 20 #include "base/string_number_conversions.h" 21 #include "base/string_piece.h" 22 #include "base/string_util.h" 23 #include "base/stringprintf.h" 24 #include "base/threading/thread.h" 25 #include "base/tracked_objects.h" 26 #include "base/utf_string_conversions.h" 27 #include "base/values.h" 28 #include "chrome/browser/about_flags.h" 29 #include "chrome/browser/browser_process.h" 30 #include "chrome/browser/defaults.h" 31 #include "chrome/browser/memory_details.h" 32 #include "chrome/browser/metrics/histogram_synchronizer.h" 33 #include "chrome/browser/net/predictor_api.h" 34 #include "chrome/browser/platform_util.h" 35 #include "chrome/browser/profiles/profile.h" 36 #include "chrome/browser/profiles/profile_manager.h" 37 #include "chrome/browser/ui/browser_dialogs.h" 38 #include "chrome/browser/ui/webui/chrome_url_data_manager.h" 39 #include "chrome/common/about_handler.h" 40 #include "chrome/common/chrome_paths.h" 41 #include "chrome/common/chrome_version_info.h" 42 #include "chrome/common/jstemplate_builder.h" 43 #include "chrome/common/net/gaia/google_service_auth_error.h" 44 #include "chrome/common/render_messages.h" 45 #include "chrome/common/url_constants.h" 46 #include "content/browser/browser_thread.h" 47 #include "content/browser/gpu_process_host.h" 48 #include "content/browser/renderer_host/render_process_host.h" 49 #include "content/browser/renderer_host/render_view_host.h" 50 #include "content/common/gpu_messages.h" 51 #include "googleurl/src/gurl.h" 52 #include "grit/browser_resources.h" 53 #include "grit/chromium_strings.h" 54 #include "grit/generated_resources.h" 55 #include "grit/locale_settings.h" 56 #include "net/base/escape.h" 57 #include "ui/base/l10n/l10n_util.h" 58 #include "ui/base/resource/resource_bundle.h" 59 #include "webkit/glue/webkit_glue.h" 60 #include "webkit/glue/plugins/plugin_list.h" 61 #include "webkit/plugins/npapi/webplugininfo.h" 62 63 #ifdef CHROME_V8 64 #include "v8/include/v8.h" 65 #endif 66 67 #if defined(OS_WIN) 68 #include "chrome/browser/enumerate_modules_model_win.h" 69 #elif defined(OS_CHROMEOS) 70 #include "chrome/browser/chromeos/cros/cros_library.h" 71 #include "chrome/browser/chromeos/cros/network_library.h" 72 #include "chrome/browser/chromeos/cros/syslogs_library.h" 73 #include "chrome/browser/chromeos/login/wizard_controller.h" 74 #include "chrome/browser/chromeos/version_loader.h" 75 #include "content/browser/zygote_host_linux.h" 76 #elif defined(OS_LINUX) 77 #include "content/browser/zygote_host_linux.h" 78 #endif 79 80 #if defined(USE_TCMALLOC) 81 #include "third_party/tcmalloc/chromium/src/google/malloc_extension.h" 82 #endif 83 84 using base::Time; 85 using base::TimeDelta; 86 87 #if defined(USE_TCMALLOC) 88 // static 89 AboutTcmallocOutputs* AboutTcmallocOutputs::GetInstance() { 90 return Singleton<AboutTcmallocOutputs>::get(); 91 } 92 93 AboutTcmallocOutputs::AboutTcmallocOutputs() {} 94 95 AboutTcmallocOutputs::~AboutTcmallocOutputs() {} 96 97 // Glue between the callback task and the method in the singleton. 98 void AboutTcmallocRendererCallback(base::ProcessId pid, 99 const std::string& output) { 100 AboutTcmallocOutputs::GetInstance()->RendererCallback(pid, output); 101 } 102 #endif 103 104 namespace { 105 106 // The (alphabetized) paths used for the about pages. 107 // Note: Keep these in sync with url_constants.h 108 const char kAppCacheInternalsPath[] = "appcache-internals"; 109 const char kBlobInternalsPath[] = "blob-internals"; 110 const char kCreditsPath[] = "credits"; 111 const char kCachePath[] = "view-http-cache"; 112 #if defined(OS_WIN) 113 const char kConflictsPath[] = "conflicts"; 114 #endif 115 const char kDnsPath[] = "dns"; 116 const char kFlagsPath[] = "flags"; 117 const char kGpuPath[] = "gpu-internals"; 118 const char kHistogramsPath[] = "histograms"; 119 const char kMemoryRedirectPath[] = "memory-redirect"; 120 const char kMemoryPath[] = "memory"; 121 const char kStatsPath[] = "stats"; 122 const char kTasksPath[] = "tasks"; 123 const char kTcmallocPath[] = "tcmalloc"; 124 const char kTermsPath[] = "terms"; 125 const char kVersionPath[] = "version"; 126 const char kAboutPath[] = "about"; 127 // Not about:* pages, but included to make about:about look nicer 128 const char kNetInternalsPath[] = "net-internals"; 129 const char kPluginsPath[] = "plugins"; 130 const char kSyncInternalsPath[] = "sync-internals"; 131 132 #if defined(OS_LINUX) 133 const char kLinuxProxyConfigPath[] = "linux-proxy-config"; 134 const char kSandboxPath[] = "sandbox"; 135 #endif 136 137 #if defined(OS_CHROMEOS) 138 const char kNetworkPath[] = "network"; 139 const char kOSCreditsPath[] = "os-credits"; 140 const char kEULAPathFormat[] = "/usr/share/chromeos-assets/eula/%s/eula.html"; 141 #endif 142 143 // Add path here to be included in about:about 144 const char *kAllAboutPaths[] = { 145 kAboutPath, 146 kAppCacheInternalsPath, 147 kBlobInternalsPath, 148 kCachePath, 149 kCreditsPath, 150 #if defined(OS_WIN) 151 kConflictsPath, 152 #endif 153 kDnsPath, 154 kFlagsPath, 155 kGpuPath, 156 kHistogramsPath, 157 kMemoryPath, 158 kNetInternalsPath, 159 kPluginsPath, 160 kStatsPath, 161 kSyncInternalsPath, 162 #ifdef TRACK_ALL_TASK_OBJECTS 163 kTasksPath, 164 #endif // TRACK_ALL_TASK_OBJECTS 165 kTcmallocPath, 166 kTermsPath, 167 kVersionPath, 168 #if defined(OS_LINUX) 169 kSandboxPath, 170 #endif 171 #if defined(OS_CHROMEOS) 172 kNetworkPath, 173 kOSCreditsPath, 174 #endif 175 }; 176 177 // When you type about:memory, it actually loads an intermediate URL that 178 // redirects you to the final page. This avoids the problem where typing 179 // "about:memory" on the new tab page or any other page where a process 180 // transition would occur to the about URL will cause some confusion. 181 // 182 // The problem is that during the processing of the memory page, there are two 183 // processes active, the original and the destination one. This can create the 184 // impression that we're using more resources than we actually are. This 185 // redirect solves the problem by eliminating the process transition during the 186 // time that about memory is being computed. 187 std::string GetAboutMemoryRedirectResponse() { 188 return "<meta http-equiv=\"refresh\" " 189 "content=\"0;chrome://about/memory\">"; 190 } 191 192 class AboutSource : public ChromeURLDataManager::DataSource { 193 public: 194 // Creates our datasource. 195 AboutSource(); 196 197 // Called when the network layer has requested a resource underneath 198 // the path we registered. 199 virtual void StartDataRequest(const std::string& path, 200 bool is_incognito, 201 int request_id); 202 203 virtual std::string GetMimeType(const std::string&) const { 204 return "text/html"; 205 } 206 207 // Send the response data. 208 void FinishDataRequest(const std::string& html, int request_id); 209 210 private: 211 virtual ~AboutSource(); 212 213 DISALLOW_COPY_AND_ASSIGN(AboutSource); 214 }; 215 216 // Handling about:memory is complicated enough to encapsulate its related 217 // methods into a single class. The user should create it (on the heap) and call 218 // its |StartFetch()| method. 219 class AboutMemoryHandler : public MemoryDetails { 220 public: 221 AboutMemoryHandler(AboutSource* source, int request_id) 222 : source_(source), request_id_(request_id) {} 223 224 225 virtual void OnDetailsAvailable(); 226 227 private: 228 ~AboutMemoryHandler() {} 229 230 void BindProcessMetrics(DictionaryValue* data, 231 ProcessMemoryInformation* info); 232 void AppendProcess(ListValue* child_data, ProcessMemoryInformation* info); 233 234 scoped_refptr<AboutSource> source_; 235 int request_id_; 236 237 DISALLOW_COPY_AND_ASSIGN(AboutMemoryHandler); 238 }; 239 240 #if defined(OS_CHROMEOS) 241 // ChromeOSAboutVersionHandler is responsible for loading the Chrome OS 242 // version. 243 // ChromeOSAboutVersionHandler handles deleting itself once the version has 244 // been obtained and AboutSource notified. 245 class ChromeOSAboutVersionHandler { 246 public: 247 ChromeOSAboutVersionHandler(AboutSource* source, int request_id); 248 249 // Callback from chromeos::VersionLoader giving the version. 250 void OnVersion(chromeos::VersionLoader::Handle handle, 251 std::string version); 252 253 private: 254 // Where the results are fed to. 255 scoped_refptr<AboutSource> source_; 256 257 // ID identifying the request. 258 int request_id_; 259 260 // Handles asynchronously loading the version. 261 chromeos::VersionLoader loader_; 262 263 // Used to request the version. 264 CancelableRequestConsumer consumer_; 265 266 DISALLOW_COPY_AND_ASSIGN(ChromeOSAboutVersionHandler); 267 }; 268 269 class ChromeOSTermsHandler 270 : public base::RefCountedThreadSafe<ChromeOSTermsHandler> { 271 public: 272 static void Start(AboutSource* source, int request_id) { 273 scoped_refptr<ChromeOSTermsHandler> handler( 274 new ChromeOSTermsHandler(source, request_id)); 275 handler->StartOnUIThread(); 276 } 277 278 private: 279 ChromeOSTermsHandler(AboutSource* source, int request_id) 280 : source_(source), 281 request_id_(request_id), 282 locale_(WizardController::GetInitialLocale()) { 283 } 284 285 void StartOnUIThread() { 286 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 287 BrowserThread::PostTask( 288 BrowserThread::FILE, FROM_HERE, 289 NewRunnableMethod(this, &ChromeOSTermsHandler::LoadFileOnFileThread)); 290 } 291 292 void LoadFileOnFileThread() { 293 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 294 std::string path = StringPrintf(kEULAPathFormat, locale_.c_str()); 295 if (!file_util::ReadFileToString(FilePath(path), &contents_)) { 296 // No EULA for given language - try en-US as default. 297 path = StringPrintf(kEULAPathFormat, "en-US"); 298 if (!file_util::ReadFileToString(FilePath(path), &contents_)) { 299 // File with EULA not found, ResponseOnUIThread will load EULA from 300 // resources if contents_ is empty. 301 contents_.clear(); 302 } 303 } 304 BrowserThread::PostTask( 305 BrowserThread::UI, FROM_HERE, 306 NewRunnableMethod(this, &ChromeOSTermsHandler::ResponseOnUIThread)); 307 } 308 309 void ResponseOnUIThread() { 310 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 311 if (contents_.empty()) { 312 contents_ = ResourceBundle::GetSharedInstance().GetRawDataResource( 313 IDR_TERMS_HTML).as_string(); 314 } 315 source_->FinishDataRequest(contents_, request_id_); 316 } 317 318 // Where the results are fed to. 319 scoped_refptr<AboutSource> source_; 320 321 // ID identifying the request. 322 int request_id_; 323 324 std::string locale_; 325 326 std::string contents_; 327 328 DISALLOW_COPY_AND_ASSIGN(ChromeOSTermsHandler); 329 }; 330 331 #endif 332 333 // Individual about handlers --------------------------------------------------- 334 335 std::string AboutAbout() { 336 std::string html("<html><head><title>About Pages</title></head>\n" 337 "<body><h2>List of About pages</h2>\n<ul>"); 338 std::vector<std::string> paths(AboutPaths()); 339 for (std::vector<std::string>::const_iterator i = paths.begin(); 340 i != paths.end(); ++i) { 341 html += "<li><a href='chrome://"; 342 if ((*i != kAppCacheInternalsPath) && 343 (*i != kBlobInternalsPath) && 344 (*i != kCachePath) && 345 #if defined(OS_WIN) 346 (*i != kConflictsPath) && 347 #endif 348 (*i != kFlagsPath) && 349 (*i != kGpuPath) && 350 (*i != kNetInternalsPath) && 351 (*i != kPluginsPath)) { 352 html += "about/"; 353 } 354 html += *i + "/'>about:" + *i + "</a></li>\n"; 355 } 356 const char *debug[] = { "crash", "kill", "hang", "shorthang", 357 "gpucrash", "gpuhang" }; 358 html += "</ul>\n<h2>For Debug</h2>\n" 359 "<p>The following pages are for debugging purposes only. Because they " 360 "crash or hang the renderer, they're not linked directly; you can type " 361 "them into the address bar if you need them.</p>\n<ul>"; 362 for (size_t i = 0; i < arraysize(debug); i++) 363 html += "<li>about:" + std::string(debug[i]) + "</li>\n"; 364 html += "</ul>\n</body></html>"; 365 return html; 366 } 367 368 #if defined(OS_CHROMEOS) 369 370 // Html output helper functions 371 // TODO(stevenjb): L10N this. 372 373 // Helper function to wrap Html with <th> tag. 374 static std::string WrapWithTH(std::string text) { 375 return "<th>" + text + "</th>"; 376 } 377 378 // Helper function to wrap Html with <td> tag. 379 static std::string WrapWithTD(std::string text) { 380 return "<td>" + text + "</td>"; 381 } 382 383 // Helper function to create an Html table header for a Network. 384 static std::string ToHtmlTableHeader(const chromeos::Network* network) { 385 std::string str = 386 WrapWithTH("Name") + 387 WrapWithTH("Active") + 388 WrapWithTH("State"); 389 if (network->type() == chromeos::TYPE_WIFI || 390 network->type() == chromeos::TYPE_CELLULAR) { 391 str += WrapWithTH("Auto-Connect"); 392 str += WrapWithTH("Strength"); 393 } 394 if (network->type() == chromeos::TYPE_WIFI) { 395 str += WrapWithTH("Encryption"); 396 str += WrapWithTH("Passphrase"); 397 str += WrapWithTH("Identity"); 398 str += WrapWithTH("Certificate"); 399 } 400 if (network->type() == chromeos::TYPE_CELLULAR) { 401 str += WrapWithTH("Technology"); 402 str += WrapWithTH("Connectivity"); 403 str += WrapWithTH("Activation"); 404 str += WrapWithTH("Roaming"); 405 } 406 if (network->type() == chromeos::TYPE_VPN) { 407 str += WrapWithTH("Host"); 408 str += WrapWithTH("Provider Type"); 409 str += WrapWithTH("PSK Passphrase"); 410 str += WrapWithTH("Username"); 411 str += WrapWithTH("User Passphrase"); 412 } 413 str += WrapWithTH("Error"); 414 str += WrapWithTH("IP Address"); 415 return str; 416 } 417 418 // Helper function to create an Html table row for a Network. 419 static std::string ToHtmlTableRow(const chromeos::Network* network) { 420 std::string str = 421 WrapWithTD(network->name()) + 422 WrapWithTD(base::IntToString(network->is_active())) + 423 WrapWithTD(network->GetStateString()); 424 if (network->type() == chromeos::TYPE_WIFI || 425 network->type() == chromeos::TYPE_CELLULAR) { 426 const chromeos::WirelessNetwork* wireless = 427 static_cast<const chromeos::WirelessNetwork*>(network); 428 str += WrapWithTD(base::IntToString(wireless->auto_connect())); 429 str += WrapWithTD(base::IntToString(wireless->strength())); 430 } 431 if (network->type() == chromeos::TYPE_WIFI) { 432 const chromeos::WifiNetwork* wifi = 433 static_cast<const chromeos::WifiNetwork*>(network); 434 str += WrapWithTD(wifi->GetEncryptionString()); 435 str += WrapWithTD(std::string(wifi->passphrase().length(), '*')); 436 str += WrapWithTD(wifi->identity()); 437 str += WrapWithTD(wifi->cert_path()); 438 } 439 if (network->type() == chromeos::TYPE_CELLULAR) { 440 const chromeos::CellularNetwork* cell = 441 static_cast<const chromeos::CellularNetwork*>(network); 442 str += WrapWithTH(cell->GetNetworkTechnologyString()); 443 str += WrapWithTH(cell->GetConnectivityStateString()); 444 str += WrapWithTH(cell->GetActivationStateString()); 445 str += WrapWithTH(cell->GetRoamingStateString()); 446 } 447 if (network->type() == chromeos::TYPE_VPN) { 448 const chromeos::VirtualNetwork* vpn = 449 static_cast<const chromeos::VirtualNetwork*>(network); 450 str += WrapWithTH(vpn->server_hostname()); 451 str += WrapWithTH(vpn->GetProviderTypeString()); 452 str += WrapWithTD(std::string(vpn->psk_passphrase().length(), '*')); 453 str += WrapWithTH(vpn->username()); 454 str += WrapWithTD(std::string(vpn->user_passphrase().length(), '*')); 455 } 456 str += WrapWithTD(network->failed() ? network->GetErrorString() : ""); 457 str += WrapWithTD(network->ip_address()); 458 return str; 459 } 460 461 std::string GetNetworkHtmlInfo(int refresh) { 462 chromeos::NetworkLibrary* cros = 463 chromeos::CrosLibrary::Get()->GetNetworkLibrary(); 464 std::string output; 465 output.append("<html><head><title>About Network</title>"); 466 if (refresh > 0) 467 output.append("<meta http-equiv=\"refresh\" content=\"" + 468 base::IntToString(refresh) + "\"/>"); 469 output.append("</head><body>"); 470 if (refresh > 0) { 471 output.append("(Auto-refreshing page every " + 472 base::IntToString(refresh) + "s)"); 473 } else { 474 output.append("(To auto-refresh this page: about:network/<secs>)"); 475 } 476 477 if (cros->ethernet_enabled()) { 478 output.append("<h3>Ethernet:</h3><table border=1>"); 479 const chromeos::EthernetNetwork* ethernet = cros->ethernet_network(); 480 if (ethernet) { 481 output.append("<tr>" + ToHtmlTableHeader(ethernet) + "</tr>"); 482 output.append("<tr>" + ToHtmlTableRow(ethernet) + "</tr>"); 483 } 484 } 485 486 if (cros->wifi_enabled()) { 487 output.append("</table><h3>Wifi Networks:</h3><table border=1>"); 488 const chromeos::WifiNetworkVector& wifi_networks = cros->wifi_networks(); 489 for (size_t i = 0; i < wifi_networks.size(); ++i) { 490 if (i == 0) 491 output.append("<tr>" + ToHtmlTableHeader(wifi_networks[i]) + 492 "</tr>"); 493 output.append("<tr>" + ToHtmlTableRow(wifi_networks[i]) + "</tr>"); 494 } 495 } 496 497 if (cros->cellular_enabled()) { 498 output.append("</table><h3>Cellular Networks:</h3><table border=1>"); 499 const chromeos::CellularNetworkVector& cellular_networks = 500 cros->cellular_networks(); 501 for (size_t i = 0; i < cellular_networks.size(); ++i) { 502 if (i == 0) 503 output.append("<tr>" + ToHtmlTableHeader(cellular_networks[i]) + 504 "</tr>"); 505 output.append("<tr>" + ToHtmlTableRow(cellular_networks[i]) + "</tr>"); 506 } 507 } 508 509 { 510 output.append("</table><h3>Virtual Networks:</h3><table border=1>"); 511 const chromeos::VirtualNetworkVector& virtual_networks = 512 cros->virtual_networks(); 513 for (size_t i = 0; i < virtual_networks.size(); ++i) { 514 if (i == 0) 515 output.append("<tr>" + ToHtmlTableHeader(virtual_networks[i]) + 516 "</tr>"); 517 output.append("<tr>" + ToHtmlTableRow(virtual_networks[i]) + "</tr>"); 518 } 519 } 520 521 { 522 output.append( 523 "</table><h3>Remembered Wi-Fi Networks:</h3><table border=1>"); 524 const chromeos::WifiNetworkVector& remembered_wifi_networks = 525 cros->remembered_wifi_networks(); 526 for (size_t i = 0; i < remembered_wifi_networks.size(); ++i) { 527 if (i == 0) 528 output.append("<tr>" + 529 ToHtmlTableHeader(remembered_wifi_networks[i]) + "</tr>"); 530 output.append("<tr>" + ToHtmlTableRow(remembered_wifi_networks[i]) + 531 "</tr>"); 532 } 533 } 534 535 output.append("</table></body></html>"); 536 return output; 537 } 538 539 std::string AboutNetwork(const std::string& query) { 540 int refresh; 541 base::StringToInt(query, &refresh); 542 return GetNetworkHtmlInfo(refresh); 543 } 544 #endif 545 546 // AboutDnsHandler bounces the request back to the IO thread to collect 547 // the DNS information. 548 class AboutDnsHandler : public base::RefCountedThreadSafe<AboutDnsHandler> { 549 public: 550 static void Start(AboutSource* source, int request_id) { 551 scoped_refptr<AboutDnsHandler> handler( 552 new AboutDnsHandler(source, request_id)); 553 handler->StartOnUIThread(); 554 } 555 556 private: 557 AboutDnsHandler(AboutSource* source, int request_id) 558 : source_(source), 559 request_id_(request_id) { 560 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 561 } 562 563 // Calls FinishOnUIThread() on completion. 564 void StartOnUIThread() { 565 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 566 BrowserThread::PostTask( 567 BrowserThread::IO, FROM_HERE, 568 NewRunnableMethod(this, &AboutDnsHandler::StartOnIOThread)); 569 } 570 571 void StartOnIOThread() { 572 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 573 574 std::string data; 575 chrome_browser_net::PredictorGetHtmlInfo(&data); 576 577 BrowserThread::PostTask( 578 BrowserThread::UI, FROM_HERE, 579 NewRunnableMethod(this, &AboutDnsHandler::FinishOnUIThread, data)); 580 } 581 582 void FinishOnUIThread(const std::string& data) { 583 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 584 source_->FinishDataRequest(data, request_id_); 585 } 586 587 // Where the results are fed to. 588 scoped_refptr<AboutSource> source_; 589 590 // ID identifying the request. 591 int request_id_; 592 593 DISALLOW_COPY_AND_ASSIGN(AboutDnsHandler); 594 }; 595 596 #if defined(USE_TCMALLOC) 597 std::string AboutTcmalloc(const std::string& query) { 598 std::string data; 599 AboutTcmallocOutputsType* outputs = 600 AboutTcmallocOutputs::GetInstance()->outputs(); 601 602 // Display any stats for which we sent off requests the last time. 603 data.append("<html><head><title>About tcmalloc</title></head><body>\n"); 604 data.append("<p>Stats as of last page load;"); 605 data.append("reload to get stats as of this page load.</p>\n"); 606 data.append("<table width=\"100%\">\n"); 607 for (AboutTcmallocOutputsType::const_iterator oit = outputs->begin(); 608 oit != outputs->end(); 609 oit++) { 610 data.append("<tr><td bgcolor=\"yellow\">"); 611 data.append(oit->first); 612 data.append("</td></tr>\n"); 613 data.append("<tr><td><pre>\n"); 614 data.append(oit->second); 615 data.append("</pre></td></tr>\n"); 616 } 617 data.append("</table>\n"); 618 data.append("</body></html>\n"); 619 620 // Reset our collector singleton. 621 outputs->clear(); 622 623 // Populate the collector with stats from the local browser process 624 // and send off requests to all the renderer processes. 625 char buffer[1024 * 32]; 626 MallocExtension::instance()->GetStats(buffer, sizeof(buffer)); 627 std::string browser("Browser"); 628 AboutTcmallocOutputs::GetInstance()->SetOutput(browser, buffer); 629 RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator()); 630 while (!it.IsAtEnd()) { 631 it.GetCurrentValue()->Send(new ViewMsg_GetRendererTcmalloc); 632 it.Advance(); 633 } 634 635 return data; 636 } 637 #endif 638 639 std::string AboutHistograms(const std::string& query) { 640 TimeDelta wait_time = TimeDelta::FromMilliseconds(10000); 641 642 HistogramSynchronizer* current_synchronizer = 643 HistogramSynchronizer::CurrentSynchronizer(); 644 DCHECK(current_synchronizer != NULL); 645 current_synchronizer->FetchRendererHistogramsSynchronously(wait_time); 646 647 std::string data; 648 base::StatisticsRecorder::WriteHTMLGraph(query, &data); 649 return data; 650 } 651 652 void AboutMemory(AboutSource* source, int request_id) { 653 // The AboutMemoryHandler cleans itself up, but |StartFetch()| will want the 654 // refcount to be greater than 0. 655 scoped_refptr<AboutMemoryHandler> 656 handler(new AboutMemoryHandler(source, request_id)); 657 handler->StartFetch(); 658 } 659 660 #ifdef TRACK_ALL_TASK_OBJECTS 661 static std::string AboutObjects(const std::string& query) { 662 std::string data; 663 tracked_objects::ThreadData::WriteHTML(query, &data); 664 return data; 665 } 666 #endif // TRACK_ALL_TASK_OBJECTS 667 668 // Handler for filling in the "about:stats" page, as called by the browser's 669 // About handler processing. 670 // |query| is roughly the query string of the about:stats URL. 671 // Returns a string containing the HTML to render for the about:stats page. 672 // Conditional Output: 673 // if |query| is "json", returns a JSON format of all counters. 674 // if |query| is "raw", returns plain text of counter deltas. 675 // otherwise, returns HTML with pretty JS/HTML to display the data. 676 std::string AboutStats(const std::string& query) { 677 // We keep the DictionaryValue tree live so that we can do delta 678 // stats computations across runs. 679 static DictionaryValue root; 680 static base::TimeTicks last_sample_time = base::TimeTicks::Now(); 681 682 base::TimeTicks now = base::TimeTicks::Now(); 683 base::TimeDelta time_since_last_sample = now - last_sample_time; 684 last_sample_time = now; 685 686 base::StatsTable* table = base::StatsTable::current(); 687 if (!table) 688 return std::string(); 689 690 // We maintain two lists - one for counters and one for timers. 691 // Timers actually get stored on both lists. 692 ListValue* counters; 693 if (!root.GetList("counters", &counters)) { 694 counters = new ListValue(); 695 root.Set("counters", counters); 696 } 697 698 ListValue* timers; 699 if (!root.GetList("timers", &timers)) { 700 timers = new ListValue(); 701 root.Set("timers", timers); 702 } 703 704 // NOTE: Counters start at index 1. 705 for (int index = 1; index <= table->GetMaxCounters(); index++) { 706 // Get the counter's full name 707 std::string full_name = table->GetRowName(index); 708 if (full_name.length() == 0) 709 break; 710 DCHECK_EQ(':', full_name[1]); 711 char counter_type = full_name[0]; 712 std::string name = full_name.substr(2); 713 714 // JSON doesn't allow '.' in names. 715 size_t pos; 716 while ((pos = name.find(".")) != std::string::npos) 717 name.replace(pos, 1, ":"); 718 719 // Try to see if this name already exists. 720 DictionaryValue* counter = NULL; 721 for (size_t scan_index = 0; 722 scan_index < counters->GetSize(); scan_index++) { 723 DictionaryValue* dictionary; 724 if (counters->GetDictionary(scan_index, &dictionary)) { 725 std::string scan_name; 726 if (dictionary->GetString("name", &scan_name) && scan_name == name) { 727 counter = dictionary; 728 } 729 } else { 730 NOTREACHED(); // Should always be there 731 } 732 } 733 734 if (counter == NULL) { 735 counter = new DictionaryValue(); 736 counter->SetString("name", name); 737 counters->Append(counter); 738 } 739 740 switch (counter_type) { 741 case 'c': 742 { 743 int new_value = table->GetRowValue(index); 744 int prior_value = 0; 745 int delta = 0; 746 if (counter->GetInteger("value", &prior_value)) { 747 delta = new_value - prior_value; 748 } 749 counter->SetInteger("value", new_value); 750 counter->SetInteger("delta", delta); 751 } 752 break; 753 case 'm': 754 { 755 // TODO(mbelshe): implement me. 756 } 757 break; 758 case 't': 759 { 760 int time = table->GetRowValue(index); 761 counter->SetInteger("time", time); 762 763 // Store this on the timers list as well. 764 timers->Append(counter); 765 } 766 break; 767 default: 768 NOTREACHED(); 769 } 770 } 771 772 std::string data; 773 if (query == "json") { 774 base::JSONWriter::WriteWithOptionalEscape(&root, true, false, &data); 775 } else if (query == "raw") { 776 // Dump the raw counters which have changed in text format. 777 data = "<pre>"; 778 data.append(StringPrintf("Counter changes in the last %ldms\n", 779 static_cast<long int>(time_since_last_sample.InMilliseconds()))); 780 for (size_t i = 0; i < counters->GetSize(); ++i) { 781 Value* entry = NULL; 782 bool rv = counters->Get(i, &entry); 783 if (!rv) 784 continue; // None of these should fail. 785 DictionaryValue* counter = static_cast<DictionaryValue*>(entry); 786 int delta; 787 rv = counter->GetInteger("delta", &delta); 788 if (!rv) 789 continue; 790 if (delta > 0) { 791 std::string name; 792 rv = counter->GetString("name", &name); 793 if (!rv) 794 continue; 795 int value; 796 rv = counter->GetInteger("value", &value); 797 if (!rv) 798 continue; 799 data.append(name); 800 data.append(":"); 801 data.append(base::IntToString(delta)); 802 data.append("\n"); 803 } 804 } 805 data.append("</pre>"); 806 } else { 807 // Get about_stats.html and process a pretty page. 808 static const base::StringPiece stats_html( 809 ResourceBundle::GetSharedInstance().GetRawDataResource( 810 IDR_ABOUT_STATS_HTML)); 811 812 // Create jstemplate and return. 813 data = jstemplate_builder::GetTemplateHtml( 814 stats_html, &root, "t" /* template root node id */); 815 816 // Clear the timer list since we stored the data in the timers list as well. 817 for (int index = static_cast<int>(timers->GetSize())-1; index >= 0; 818 index--) { 819 Value* value; 820 timers->Remove(index, &value); 821 // We don't care about the value pointer; it's still tracked 822 // on the counters list. 823 } 824 } 825 826 return data; 827 } 828 829 #if defined(OS_LINUX) 830 std::string AboutLinuxProxyConfig() { 831 std::string data; 832 data.append("<!DOCTYPE HTML>\n"); 833 data.append("<html><head><meta charset=\"utf-8\"><title>"); 834 data.append(l10n_util::GetStringUTF8(IDS_ABOUT_LINUX_PROXY_CONFIG_TITLE)); 835 data.append("</title>"); 836 data.append("<style>body { max-width: 70ex; padding: 2ex 5ex; }</style>"); 837 data.append("</head><body>\n"); 838 FilePath binary = CommandLine::ForCurrentProcess()->GetProgram(); 839 data.append(l10n_util::GetStringFUTF8( 840 IDS_ABOUT_LINUX_PROXY_CONFIG_BODY, 841 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME), 842 ASCIIToUTF16(binary.BaseName().value()))); 843 data.append("</body></html>\n"); 844 return data; 845 } 846 847 void AboutSandboxRow(std::string* data, const std::string& prefix, int name_id, 848 bool good) { 849 data->append("<tr><td>"); 850 data->append(prefix); 851 data->append(l10n_util::GetStringUTF8(name_id)); 852 if (good) { 853 data->append("</td><td style=\"color: green;\">"); 854 data->append( 855 l10n_util::GetStringUTF8(IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL)); 856 } else { 857 data->append("</td><td style=\"color: red;\">"); 858 data->append( 859 l10n_util::GetStringUTF8(IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL)); 860 } 861 data->append("</td></tr>"); 862 } 863 864 std::string AboutSandbox() { 865 std::string data; 866 data.append("<!DOCTYPE HTML>\n"); 867 data.append("<html><head><meta charset=\"utf-8\"><title>"); 868 data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_TITLE)); 869 data.append("</title>"); 870 data.append("</head><body>\n"); 871 data.append("<h1>"); 872 data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_TITLE)); 873 data.append("</h1>"); 874 875 const int status = ZygoteHost::GetInstance()->sandbox_status(); 876 877 data.append("<table>"); 878 879 AboutSandboxRow(&data, "", IDS_ABOUT_SANDBOX_SUID_SANDBOX, 880 status & ZygoteHost::kSandboxSUID); 881 if (status & ZygoteHost::kSandboxPIDNS) { 882 AboutSandboxRow(&data, " ", IDS_ABOUT_SANDBOX_PID_NAMESPACES, 883 status & ZygoteHost::kSandboxPIDNS); 884 AboutSandboxRow(&data, " ", IDS_ABOUT_SANDBOX_NET_NAMESPACES, 885 status & ZygoteHost::kSandboxNetNS); 886 } 887 AboutSandboxRow(&data, "", IDS_ABOUT_SANDBOX_SECCOMP_SANDBOX, 888 status & ZygoteHost::kSandboxSeccomp); 889 890 data.append("</table>"); 891 892 bool good = ((status & ZygoteHost::kSandboxSUID) && 893 (status & ZygoteHost::kSandboxPIDNS)) || 894 (status & ZygoteHost::kSandboxSeccomp); 895 if (good) { 896 data.append("<p style=\"color: green\">"); 897 data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_OK)); 898 } else { 899 data.append("<p style=\"color: red\">"); 900 data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_BAD)); 901 } 902 data.append("</p>"); 903 904 data.append("</body></html>\n"); 905 return data; 906 } 907 #endif 908 909 std::string AboutVersion(DictionaryValue* localized_strings) { 910 localized_strings->SetString("title", 911 l10n_util::GetStringUTF16(IDS_ABOUT_VERSION_TITLE)); 912 chrome::VersionInfo version_info; 913 914 std::string webkit_version = webkit_glue::GetWebKitVersion(); 915 #ifdef CHROME_V8 916 std::string js_version(v8::V8::GetVersion()); 917 std::string js_engine = "V8"; 918 #else 919 std::string js_version = webkit_version; 920 std::string js_engine = "JavaScriptCore"; 921 #endif 922 923 localized_strings->SetString("name", 924 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)); 925 localized_strings->SetString("version", version_info.Version()); 926 // Bug 79458: Need to evaluate the use of getting the version string on 927 // this thread. 928 base::ThreadRestrictions::ScopedAllowIO allow_io; 929 localized_strings->SetString("version_modifier", 930 platform_util::GetVersionStringModifier()); 931 localized_strings->SetString("js_engine", js_engine); 932 localized_strings->SetString("js_version", js_version); 933 934 // Obtain the version of the first enabled Flash plugin. 935 std::vector<webkit::npapi::WebPluginInfo> info_array; 936 webkit::npapi::PluginList::Singleton()->GetPluginInfoArray( 937 GURL(), "application/x-shockwave-flash", false, &info_array, NULL); 938 string16 flash_version = 939 l10n_util::GetStringUTF16(IDS_PLUGINS_DISABLED_PLUGIN); 940 for (size_t i = 0; i < info_array.size(); ++i) { 941 if (webkit::npapi::IsPluginEnabled(info_array[i])) { 942 flash_version = info_array[i].version; 943 break; 944 } 945 } 946 localized_strings->SetString("flash_plugin", "Flash"); 947 localized_strings->SetString("flash_version", flash_version); 948 localized_strings->SetString("webkit_version", webkit_version); 949 localized_strings->SetString("company", 950 l10n_util::GetStringUTF16(IDS_ABOUT_VERSION_COMPANY_NAME)); 951 localized_strings->SetString("copyright", 952 l10n_util::GetStringUTF16(IDS_ABOUT_VERSION_COPYRIGHT)); 953 localized_strings->SetString("cl", version_info.LastChange()); 954 localized_strings->SetString("official", 955 l10n_util::GetStringUTF16( 956 version_info.IsOfficialBuild() ? 957 IDS_ABOUT_VERSION_OFFICIAL 958 : IDS_ABOUT_VERSION_UNOFFICIAL)); 959 localized_strings->SetString("user_agent_name", 960 l10n_util::GetStringUTF16(IDS_ABOUT_VERSION_USER_AGENT)); 961 localized_strings->SetString("useragent", webkit_glue::GetUserAgent(GURL())); 962 localized_strings->SetString("command_line_name", 963 l10n_util::GetStringUTF16(IDS_ABOUT_VERSION_COMMAND_LINE)); 964 965 #if defined(OS_WIN) 966 localized_strings->SetString("command_line", 967 WideToUTF16(CommandLine::ForCurrentProcess()->command_line_string())); 968 #elif defined(OS_POSIX) 969 std::string command_line = ""; 970 typedef std::vector<std::string> ArgvList; 971 const ArgvList& argv = CommandLine::ForCurrentProcess()->argv(); 972 for (ArgvList::const_iterator iter = argv.begin(); iter != argv.end(); iter++) 973 command_line += " " + *iter; 974 // TODO(viettrungluu): |command_line| could really have any encoding, whereas 975 // below we assumes it's UTF-8. 976 localized_strings->SetString("command_line", command_line); 977 #endif 978 979 base::StringPiece version_html( 980 ResourceBundle::GetSharedInstance().GetRawDataResource( 981 IDR_ABOUT_VERSION_HTML)); 982 983 return jstemplate_builder::GetTemplatesHtml( 984 version_html, localized_strings, "t" /* template root node id */); 985 } 986 987 std::string VersionNumberToString(uint32 value) { 988 int hi = (value >> 8) & 0xff; 989 int low = value & 0xff; 990 return base::IntToString(hi) + "." + base::IntToString(low); 991 } 992 993 // AboutSource ----------------------------------------------------------------- 994 995 AboutSource::AboutSource() 996 : DataSource(chrome::kAboutScheme, MessageLoop::current()) { 997 } 998 999 AboutSource::~AboutSource() { 1000 } 1001 1002 void AboutSource::StartDataRequest(const std::string& path_raw, 1003 bool is_incognito, int request_id) { 1004 std::string path = path_raw; 1005 std::string info; 1006 if (path.find("/") != std::string::npos) { 1007 size_t pos = path.find("/"); 1008 info = path.substr(pos + 1, path.length() - (pos + 1)); 1009 path = path.substr(0, pos); 1010 } 1011 path = StringToLowerASCII(path); 1012 1013 std::string response; 1014 if (path == kDnsPath) { 1015 AboutDnsHandler::Start(this, request_id); 1016 return; 1017 } else if (path == kHistogramsPath) { 1018 response = AboutHistograms(info); 1019 } else if (path == kMemoryPath) { 1020 AboutMemory(this, request_id); 1021 return; 1022 } else if (path == kMemoryRedirectPath) { 1023 response = GetAboutMemoryRedirectResponse(); 1024 #ifdef TRACK_ALL_TASK_OBJECTS 1025 } else if (path == kTasksPath) { 1026 response = AboutObjects(info); 1027 #endif 1028 } else if (path == kStatsPath) { 1029 response = AboutStats(info); 1030 #if defined(USE_TCMALLOC) 1031 } else if (path == kTcmallocPath) { 1032 response = AboutTcmalloc(info); 1033 #endif 1034 } else if (path == kVersionPath || path.empty()) { 1035 #if defined(OS_CHROMEOS) 1036 new ChromeOSAboutVersionHandler(this, request_id); 1037 return; 1038 #else 1039 DictionaryValue value; 1040 response = AboutVersion(&value); 1041 #endif 1042 } else if (path == kCreditsPath) { 1043 response = ResourceBundle::GetSharedInstance().GetRawDataResource( 1044 IDR_CREDITS_HTML).as_string(); 1045 } else if (path == kAboutPath) { 1046 response = AboutAbout(); 1047 #if defined(OS_CHROMEOS) 1048 } else if (path == kOSCreditsPath) { 1049 response = ResourceBundle::GetSharedInstance().GetRawDataResource( 1050 IDR_OS_CREDITS_HTML).as_string(); 1051 } else if (path == kNetworkPath) { 1052 response = AboutNetwork(info); 1053 #endif 1054 } else if (path == kTermsPath) { 1055 #if defined(OS_CHROMEOS) 1056 ChromeOSTermsHandler::Start(this, request_id); 1057 return; 1058 #else 1059 response = ResourceBundle::GetSharedInstance().GetRawDataResource( 1060 IDR_TERMS_HTML).as_string(); 1061 #endif 1062 #if defined(OS_LINUX) 1063 } else if (path == kLinuxProxyConfigPath) { 1064 response = AboutLinuxProxyConfig(); 1065 } else if (path == kSandboxPath) { 1066 response = AboutSandbox(); 1067 #endif 1068 } 1069 1070 FinishDataRequest(response, request_id); 1071 } 1072 1073 void AboutSource::FinishDataRequest(const std::string& response, 1074 int request_id) { 1075 scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes); 1076 html_bytes->data.resize(response.size()); 1077 std::copy(response.begin(), response.end(), html_bytes->data.begin()); 1078 SendResponse(request_id, html_bytes); 1079 } 1080 1081 // AboutMemoryHandler ---------------------------------------------------------- 1082 1083 // Helper for AboutMemory to bind results from a ProcessMetrics object 1084 // to a DictionaryValue. Fills ws_usage and comm_usage so that the objects 1085 // can be used in caller's scope (e.g for appending to a net total). 1086 void AboutMemoryHandler::BindProcessMetrics(DictionaryValue* data, 1087 ProcessMemoryInformation* info) { 1088 DCHECK(data && info); 1089 1090 // Bind metrics to dictionary. 1091 data->SetInteger("ws_priv", static_cast<int>(info->working_set.priv)); 1092 data->SetInteger("ws_shareable", 1093 static_cast<int>(info->working_set.shareable)); 1094 data->SetInteger("ws_shared", static_cast<int>(info->working_set.shared)); 1095 data->SetInteger("comm_priv", static_cast<int>(info->committed.priv)); 1096 data->SetInteger("comm_map", static_cast<int>(info->committed.mapped)); 1097 data->SetInteger("comm_image", static_cast<int>(info->committed.image)); 1098 data->SetInteger("pid", info->pid); 1099 data->SetString("version", info->version); 1100 data->SetInteger("processes", info->num_processes); 1101 } 1102 1103 // Helper for AboutMemory to append memory usage information for all 1104 // sub-processes (i.e. renderers, plugins) used by Chrome. 1105 void AboutMemoryHandler::AppendProcess(ListValue* child_data, 1106 ProcessMemoryInformation* info) { 1107 DCHECK(child_data && info); 1108 1109 // Append a new DictionaryValue for this renderer to our list. 1110 DictionaryValue* child = new DictionaryValue(); 1111 child_data->Append(child); 1112 BindProcessMetrics(child, info); 1113 1114 std::string child_label( 1115 ChildProcessInfo::GetFullTypeNameInEnglish(info->type, 1116 info->renderer_type)); 1117 if (info->is_diagnostics) 1118 child_label.append(" (diagnostics)"); 1119 child->SetString("child_name", child_label); 1120 ListValue* titles = new ListValue(); 1121 child->Set("titles", titles); 1122 for (size_t i = 0; i < info->titles.size(); ++i) 1123 titles->Append(new StringValue(info->titles[i])); 1124 } 1125 1126 1127 void AboutMemoryHandler::OnDetailsAvailable() { 1128 // the root of the JSON hierarchy for about:memory jstemplate 1129 DictionaryValue root; 1130 ListValue* browsers = new ListValue(); 1131 root.Set("browsers", browsers); 1132 1133 const std::vector<ProcessData>& browser_processes = processes(); 1134 1135 // Aggregate per-process data into browser summary data. 1136 std::wstring log_string; 1137 for (size_t index = 0; index < browser_processes.size(); index++) { 1138 if (browser_processes[index].processes.empty()) 1139 continue; 1140 1141 // Sum the information for the processes within this browser. 1142 ProcessMemoryInformation aggregate; 1143 ProcessMemoryInformationList::const_iterator iterator; 1144 iterator = browser_processes[index].processes.begin(); 1145 aggregate.pid = iterator->pid; 1146 aggregate.version = iterator->version; 1147 while (iterator != browser_processes[index].processes.end()) { 1148 if (!iterator->is_diagnostics || 1149 browser_processes[index].processes.size() == 1) { 1150 aggregate.working_set.priv += iterator->working_set.priv; 1151 aggregate.working_set.shared += iterator->working_set.shared; 1152 aggregate.working_set.shareable += iterator->working_set.shareable; 1153 aggregate.committed.priv += iterator->committed.priv; 1154 aggregate.committed.mapped += iterator->committed.mapped; 1155 aggregate.committed.image += iterator->committed.image; 1156 aggregate.num_processes++; 1157 } 1158 ++iterator; 1159 } 1160 DictionaryValue* browser_data = new DictionaryValue(); 1161 browsers->Append(browser_data); 1162 browser_data->SetString("name", browser_processes[index].name); 1163 1164 BindProcessMetrics(browser_data, &aggregate); 1165 1166 // We log memory info as we record it. 1167 if (log_string.length() > 0) 1168 log_string.append(L", "); 1169 log_string.append(UTF16ToWide(browser_processes[index].name)); 1170 log_string.append(L", "); 1171 log_string.append(UTF8ToWide( 1172 base::Int64ToString(aggregate.working_set.priv))); 1173 log_string.append(L", "); 1174 log_string.append(UTF8ToWide( 1175 base::Int64ToString(aggregate.working_set.shared))); 1176 log_string.append(L", "); 1177 log_string.append(UTF8ToWide( 1178 base::Int64ToString(aggregate.working_set.shareable))); 1179 } 1180 if (log_string.length() > 0) 1181 VLOG(1) << "memory: " << log_string; 1182 1183 // Set the browser & renderer detailed process data. 1184 DictionaryValue* browser_data = new DictionaryValue(); 1185 root.Set("browzr_data", browser_data); 1186 ListValue* child_data = new ListValue(); 1187 root.Set("child_data", child_data); 1188 1189 ProcessData process = browser_processes[0]; // Chrome is the first browser. 1190 root.SetString("current_browser_name", process.name); 1191 1192 for (size_t index = 0; index < process.processes.size(); index++) { 1193 if (process.processes[index].type == ChildProcessInfo::BROWSER_PROCESS) 1194 BindProcessMetrics(browser_data, &process.processes[index]); 1195 else 1196 AppendProcess(child_data, &process.processes[index]); 1197 } 1198 1199 root.SetBoolean("show_other_browsers", 1200 browser_defaults::kShowOtherBrowsersInAboutMemory); 1201 1202 // Get about_memory.html 1203 static const base::StringPiece memory_html( 1204 ResourceBundle::GetSharedInstance().GetRawDataResource( 1205 IDR_ABOUT_MEMORY_HTML)); 1206 1207 // Create jstemplate and return. 1208 std::string template_html = jstemplate_builder::GetTemplateHtml( 1209 memory_html, &root, "t" /* template root node id */); 1210 1211 source_->FinishDataRequest(template_html, request_id_); 1212 } 1213 1214 #if defined(OS_CHROMEOS) 1215 // ChromeOSAboutVersionHandler ----------------------------------------------- 1216 1217 ChromeOSAboutVersionHandler::ChromeOSAboutVersionHandler(AboutSource* source, 1218 int request_id) 1219 : source_(source), 1220 request_id_(request_id) { 1221 loader_.EnablePlatformVersions(true); 1222 loader_.GetVersion(&consumer_, 1223 NewCallback(this, &ChromeOSAboutVersionHandler::OnVersion), 1224 chromeos::VersionLoader::VERSION_FULL); 1225 } 1226 1227 void ChromeOSAboutVersionHandler::OnVersion( 1228 chromeos::VersionLoader::Handle handle, 1229 std::string version) { 1230 DictionaryValue localized_strings; 1231 localized_strings.SetString("os_name", 1232 l10n_util::GetStringUTF16(IDS_PRODUCT_OS_NAME)); 1233 localized_strings.SetString("os_version", version); 1234 localized_strings.SetBoolean("is_chrome_os", true); 1235 source_->FinishDataRequest(AboutVersion(&localized_strings), request_id_); 1236 1237 // CancelableRequestProvider isn't happy when it's deleted and servicing a 1238 // task, so we delay the deletion. 1239 MessageLoop::current()->DeleteSoon(FROM_HERE, this); 1240 } 1241 1242 #endif 1243 1244 // Returns true if |url|'s spec starts with |about_specifier|, and is 1245 // terminated by the start of a path. 1246 bool StartsWithAboutSpecifier(const GURL& url, const char* about_specifier) { 1247 return StartsWithASCII(url.spec(), about_specifier, true) && 1248 (url.spec().size() == strlen(about_specifier) || 1249 url.spec()[strlen(about_specifier)] == '/'); 1250 } 1251 1252 // Transforms a URL of the form "about:foo/XXX" to <url_prefix> + "XXX". 1253 GURL RemapAboutURL(const std::string& url_prefix, const GURL& url) { 1254 std::string path; 1255 size_t split = url.spec().find('/'); 1256 if (split != std::string::npos) 1257 path = url.spec().substr(split + 1); 1258 return GURL(url_prefix + path); 1259 } 1260 1261 } // namespace 1262 1263 // ----------------------------------------------------------------------------- 1264 1265 bool WillHandleBrowserAboutURL(GURL* url, Profile* profile) { 1266 // We only handle about: schemes. 1267 if (!url->SchemeIs(chrome::kAboutScheme)) 1268 return false; 1269 1270 // about:blank is special. Frames are allowed to access about:blank, 1271 // but they are not allowed to access other types of about pages. 1272 // Just ignore the about:blank and let the TAB_CONTENTS_WEB handle it. 1273 if (LowerCaseEqualsASCII(url->spec(), chrome::kAboutBlankURL)) 1274 return false; 1275 1276 // Rewrite about:cache/* URLs to chrome://view-http-cache/* 1277 if (StartsWithAboutSpecifier(*url, chrome::kAboutCacheURL)) { 1278 *url = RemapAboutURL(chrome::kNetworkViewCacheURL, *url); 1279 return true; 1280 } 1281 1282 #if defined(OS_WIN) 1283 // Rewrite about:conflicts/* URLs to chrome://conflicts/* 1284 if (StartsWithAboutSpecifier(*url, chrome::kAboutConflicts)) { 1285 *url = GURL(chrome::kChromeUIConflictsURL); 1286 return true; 1287 } 1288 #endif 1289 1290 // Rewrite about:flags to chrome://flags/. 1291 if (LowerCaseEqualsASCII(url->spec(), chrome::kAboutFlagsURL)) { 1292 *url = GURL(chrome::kChromeUIFlagsURL); 1293 return true; 1294 } 1295 1296 // Rewrite about:net-internals/* URLs to chrome://net-internals/* 1297 if (StartsWithAboutSpecifier(*url, chrome::kAboutNetInternalsURL)) { 1298 *url = RemapAboutURL(chrome::kNetworkViewInternalsURL, *url); 1299 return true; 1300 } 1301 1302 // Rewrite about:gpu/* URLs to chrome://gpu-internals/* 1303 if (StartsWithAboutSpecifier(*url, chrome::kAboutGpuURL)) { 1304 *url = RemapAboutURL(chrome::kGpuInternalsURL, *url); 1305 return true; 1306 } 1307 1308 // Rewrite about:appcache-internals/* URLs to chrome://appcache/* 1309 if (StartsWithAboutSpecifier(*url, chrome::kAboutAppCacheInternalsURL)) { 1310 *url = RemapAboutURL(chrome::kAppCacheViewInternalsURL, *url); 1311 return true; 1312 } 1313 1314 // Rewrite about:sync-internals/* URLs (and about:sync, too, for 1315 // legacy reasons) to chrome://sync-internals/* 1316 if (StartsWithAboutSpecifier(*url, chrome::kAboutSyncInternalsURL) || 1317 StartsWithAboutSpecifier(*url, chrome::kAboutSyncURL)) { 1318 *url = RemapAboutURL(chrome::kSyncViewInternalsURL, *url); 1319 return true; 1320 } 1321 1322 // Rewrite about:plugins to chrome://plugins/. 1323 if (LowerCaseEqualsASCII(url->spec(), chrome::kAboutPluginsURL)) { 1324 *url = GURL(chrome::kChromeUIPluginsURL); 1325 return true; 1326 } 1327 1328 // Handle URL to crash the browser process. 1329 if (LowerCaseEqualsASCII(url->spec(), chrome::kAboutBrowserCrash)) { 1330 // Induce an intentional crash in the browser process. 1331 int* bad_pointer = NULL; 1332 *bad_pointer = 42; 1333 return true; 1334 } 1335 1336 // Handle URLs to wreck the gpu process. 1337 if (LowerCaseEqualsASCII(url->spec(), chrome::kAboutGpuCrashURL)) { 1338 GpuProcessHost::SendOnIO( 1339 0, content::CAUSE_FOR_GPU_LAUNCH_ABOUT_GPUCRASH, new GpuMsg_Crash()); 1340 } 1341 if (LowerCaseEqualsASCII(url->spec(), chrome::kAboutGpuHangURL)) { 1342 GpuProcessHost::SendOnIO( 1343 0, content::CAUSE_FOR_GPU_LAUNCH_ABOUT_GPUHANG, new GpuMsg_Hang()); 1344 } 1345 1346 // There are a few about: URLs that we hand over to the renderer. If the 1347 // renderer wants them, don't do any rewriting. 1348 if (chrome_about_handler::WillHandle(*url)) 1349 return false; 1350 1351 // Anything else requires our special handler; make sure it's initialized. 1352 InitializeAboutDataSource(profile); 1353 1354 // Special case about:memory to go through a redirect before ending up on 1355 // the final page. See GetAboutMemoryRedirectResponse above for why. 1356 if (LowerCaseEqualsASCII(url->path(), kMemoryPath)) { 1357 *url = GURL("chrome://about/memory-redirect"); 1358 return true; 1359 } 1360 1361 // Rewrite the about URL to use chrome:. WebKit treats all about URLS the 1362 // same (blank page), so if we want to display content, we need another 1363 // scheme. 1364 std::string about_url = "chrome://about/"; 1365 about_url.append(url->path()); 1366 *url = GURL(about_url); 1367 return true; 1368 } 1369 1370 void InitializeAboutDataSource(Profile* profile) { 1371 profile->GetChromeURLDataManager()->AddDataSource(new AboutSource()); 1372 } 1373 1374 // This function gets called with the fixed-up chrome: URLs, so we have to 1375 // compare against those instead of "about:blah". 1376 bool HandleNonNavigationAboutURL(const GURL& url) { 1377 // about:ipc is currently buggy, so we disable it for official builds. 1378 #if !defined(OFFICIAL_BUILD) 1379 1380 #if (defined(OS_MACOSX) || defined(OS_WIN)) && defined(IPC_MESSAGE_LOG_ENABLED) 1381 if (LowerCaseEqualsASCII(url.spec(), chrome::kChromeUIIPCURL)) { 1382 // Run the dialog. This will re-use the existing one if it's already up. 1383 browser::ShowAboutIPCDialog(); 1384 return true; 1385 } 1386 #endif 1387 1388 #endif // OFFICIAL_BUILD 1389 1390 return false; 1391 } 1392 1393 std::vector<std::string> AboutPaths() { 1394 std::vector<std::string> paths; 1395 paths.reserve(arraysize(kAllAboutPaths)); 1396 for (size_t i = 0; i < arraysize(kAllAboutPaths); i++) 1397 paths.push_back(kAllAboutPaths[i]); 1398 return paths; 1399 } 1400