1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/ui/webui/net_internals/net_internals_ui.h" 6 7 #include <algorithm> 8 #include <list> 9 #include <string> 10 #include <utility> 11 #include <vector> 12 13 #include "base/base64.h" 14 #include "base/bind.h" 15 #include "base/bind_helpers.h" 16 #include "base/command_line.h" 17 #include "base/files/file.h" 18 #include "base/files/file_path.h" 19 #include "base/files/file_util.h" 20 #include "base/memory/weak_ptr.h" 21 #include "base/message_loop/message_loop.h" 22 #include "base/prefs/pref_member.h" 23 #include "base/sequenced_task_runner_helpers.h" 24 #include "base/strings/string_number_conversions.h" 25 #include "base/strings/string_piece.h" 26 #include "base/strings/string_split.h" 27 #include "base/strings/string_util.h" 28 #include "base/strings/utf_string_conversions.h" 29 #include "base/task/cancelable_task_tracker.h" 30 #include "base/values.h" 31 #include "chrome/browser/browser_process.h" 32 #include "chrome/browser/browsing_data/browsing_data_helper.h" 33 #include "chrome/browser/browsing_data/browsing_data_remover.h" 34 #include "chrome/browser/chrome_notification_types.h" 35 #include "chrome/browser/download/download_prefs.h" 36 #include "chrome/browser/io_thread.h" 37 #include "chrome/browser/net/chrome_net_log.h" 38 #include "chrome/browser/net/chrome_network_delegate.h" 39 #include "chrome/browser/net/connection_tester.h" 40 #include "chrome/browser/prerender/prerender_manager.h" 41 #include "chrome/browser/prerender/prerender_manager_factory.h" 42 #include "chrome/browser/profiles/profile.h" 43 #include "chrome/common/chrome_paths.h" 44 #include "chrome/common/chrome_version_info.h" 45 #include "chrome/common/pref_names.h" 46 #include "chrome/common/url_constants.h" 47 #include "components/onc/onc_constants.h" 48 #include "components/url_fixer/url_fixer.h" 49 #include "content/public/browser/browser_thread.h" 50 #include "content/public/browser/notification_details.h" 51 #include "content/public/browser/resource_dispatcher_host.h" 52 #include "content/public/browser/web_contents.h" 53 #include "content/public/browser/web_ui.h" 54 #include "content/public/browser/web_ui_data_source.h" 55 #include "content/public/browser/web_ui_message_handler.h" 56 #include "grit/net_internals_resources.h" 57 #include "net/base/net_errors.h" 58 #include "net/base/net_log_logger.h" 59 #include "net/base/net_util.h" 60 #include "net/disk_cache/disk_cache.h" 61 #include "net/dns/host_cache.h" 62 #include "net/dns/host_resolver.h" 63 #include "net/http/http_cache.h" 64 #include "net/http/http_network_layer.h" 65 #include "net/http/http_network_session.h" 66 #include "net/http/http_server_properties.h" 67 #include "net/http/http_stream_factory.h" 68 #include "net/http/transport_security_state.h" 69 #include "net/proxy/proxy_service.h" 70 #include "net/url_request/url_request_context.h" 71 #include "net/url_request/url_request_context_getter.h" 72 73 #if defined(OS_CHROMEOS) 74 #include "chrome/browser/chromeos/file_manager/filesystem_api_util.h" 75 #include "chrome/browser/chromeos/net/onc_utils.h" 76 #include "chrome/browser/chromeos/profiles/profile_helper.h" 77 #include "chrome/browser/chromeos/system/syslogs_provider.h" 78 #include "chrome/browser/chromeos/system_logs/debug_log_writer.h" 79 #include "chrome/browser/net/nss_context.h" 80 #include "chromeos/dbus/dbus_thread_manager.h" 81 #include "chromeos/dbus/debug_daemon_client.h" 82 #include "chromeos/network/onc/onc_certificate_importer_impl.h" 83 #include "chromeos/network/onc/onc_utils.h" 84 #include "components/user_manager/user.h" 85 #endif 86 87 #if defined(OS_WIN) 88 #include "chrome/browser/net/service_providers_win.h" 89 #endif 90 91 #if defined(ENABLE_EXTENSIONS) 92 #include "chrome/browser/extensions/extension_service.h" 93 #include "chrome/browser/ui/webui/extensions/extension_basic_info.h" 94 #include "extensions/browser/extension_registry.h" 95 #include "extensions/browser/extension_system.h" 96 #include "extensions/common/extension_set.h" 97 #endif 98 99 using base::StringValue; 100 using content::BrowserThread; 101 using content::WebContents; 102 using content::WebUIMessageHandler; 103 104 namespace { 105 106 // Delay between when an event occurs and when it is passed to the Javascript 107 // page. All events that occur during this period are grouped together and 108 // sent to the page at once, which reduces context switching and CPU usage. 109 const int kNetLogEventDelayMilliseconds = 100; 110 111 // Returns the HostCache for |context|'s primary HostResolver, or NULL if 112 // there is none. 113 net::HostCache* GetHostResolverCache(net::URLRequestContext* context) { 114 return context->host_resolver()->GetHostCache(); 115 } 116 117 std::string HashesToBase64String(const net::HashValueVector& hashes) { 118 std::string str; 119 for (size_t i = 0; i != hashes.size(); ++i) { 120 if (i != 0) 121 str += ","; 122 str += hashes[i].ToString(); 123 } 124 return str; 125 } 126 127 bool Base64StringToHashes(const std::string& hashes_str, 128 net::HashValueVector* hashes) { 129 hashes->clear(); 130 std::vector<std::string> vector_hash_str; 131 base::SplitString(hashes_str, ',', &vector_hash_str); 132 133 for (size_t i = 0; i != vector_hash_str.size(); ++i) { 134 std::string hash_str; 135 base::RemoveChars(vector_hash_str[i], " \t\r\n", &hash_str); 136 net::HashValue hash; 137 // Skip past unrecognized hash algos 138 // But return false on malformatted input 139 if (hash_str.empty()) 140 return false; 141 if (hash_str.compare(0, 5, "sha1/") != 0 && 142 hash_str.compare(0, 7, "sha256/") != 0) { 143 continue; 144 } 145 if (!hash.FromString(hash_str)) 146 return false; 147 hashes->push_back(hash); 148 } 149 return true; 150 } 151 152 // Returns a Value representing the state of a pre-existing URLRequest when 153 // net-internals was opened. 154 base::Value* GetRequestStateAsValue(const net::URLRequest* request, 155 net::NetLog::LogLevel log_level) { 156 return request->GetStateAsValue(); 157 } 158 159 // Returns true if |request1| was created before |request2|. 160 bool RequestCreatedBefore(const net::URLRequest* request1, 161 const net::URLRequest* request2) { 162 return request1->creation_time() < request2->creation_time(); 163 } 164 165 // Returns the disk cache backend for |context| if there is one, or NULL. 166 disk_cache::Backend* GetDiskCacheBackend(net::URLRequestContext* context) { 167 if (!context->http_transaction_factory()) 168 return NULL; 169 170 net::HttpCache* http_cache = context->http_transaction_factory()->GetCache(); 171 if (!http_cache) 172 return NULL; 173 174 return http_cache->GetCurrentBackend(); 175 } 176 177 // Returns the http network session for |context| if there is one. 178 // Otherwise, returns NULL. 179 net::HttpNetworkSession* GetHttpNetworkSession( 180 net::URLRequestContext* context) { 181 if (!context->http_transaction_factory()) 182 return NULL; 183 184 return context->http_transaction_factory()->GetSession(); 185 } 186 187 base::Value* ExperimentToValue(const ConnectionTester::Experiment& experiment) { 188 base::DictionaryValue* dict = new base::DictionaryValue(); 189 190 if (experiment.url.is_valid()) 191 dict->SetString("url", experiment.url.spec()); 192 193 dict->SetString("proxy_settings_experiment", 194 ConnectionTester::ProxySettingsExperimentDescription( 195 experiment.proxy_settings_experiment)); 196 dict->SetString("host_resolver_experiment", 197 ConnectionTester::HostResolverExperimentDescription( 198 experiment.host_resolver_experiment)); 199 return dict; 200 } 201 202 content::WebUIDataSource* CreateNetInternalsHTMLSource() { 203 content::WebUIDataSource* source = 204 content::WebUIDataSource::Create(chrome::kChromeUINetInternalsHost); 205 206 source->SetUseJsonJSFormatV2(); 207 source->SetDefaultResource(IDR_NET_INTERNALS_INDEX_HTML); 208 source->AddResourcePath("index.js", IDR_NET_INTERNALS_INDEX_JS); 209 source->SetJsonPath("strings.js"); 210 return source; 211 } 212 213 // This class receives javascript messages from the renderer. 214 // Note that the WebUI infrastructure runs on the UI thread, therefore all of 215 // this class's methods are expected to run on the UI thread. 216 // 217 // Since the network code we want to run lives on the IO thread, we proxy 218 // almost everything over to NetInternalsMessageHandler::IOThreadImpl, which 219 // runs on the IO thread. 220 // 221 // TODO(eroman): Can we start on the IO thread to begin with? 222 class NetInternalsMessageHandler 223 : public WebUIMessageHandler, 224 public base::SupportsWeakPtr<NetInternalsMessageHandler> { 225 public: 226 NetInternalsMessageHandler(); 227 virtual ~NetInternalsMessageHandler(); 228 229 // WebUIMessageHandler implementation. 230 virtual void RegisterMessages() OVERRIDE; 231 232 // Calls g_browser.receive in the renderer, passing in |command| and |arg|. 233 // Takes ownership of |arg|. If the renderer is displaying a log file, the 234 // message will be ignored. 235 void SendJavascriptCommand(const std::string& command, base::Value* arg); 236 237 // Javascript message handlers. 238 void OnRendererReady(const base::ListValue* list); 239 void OnClearBrowserCache(const base::ListValue* list); 240 void OnGetPrerenderInfo(const base::ListValue* list); 241 void OnGetHistoricNetworkStats(const base::ListValue* list); 242 void OnGetExtensionInfo(const base::ListValue* list); 243 #if defined(OS_CHROMEOS) 244 void OnRefreshSystemLogs(const base::ListValue* list); 245 void OnGetSystemLog(const base::ListValue* list); 246 void OnImportONCFile(const base::ListValue* list); 247 void OnStoreDebugLogs(const base::ListValue* list); 248 void OnStoreDebugLogsCompleted(const base::FilePath& log_path, 249 bool succeeded); 250 void OnSetNetworkDebugMode(const base::ListValue* list); 251 void OnSetNetworkDebugModeCompleted(const std::string& subsystem, 252 bool succeeded); 253 254 // Callback to |GetNSSCertDatabaseForProfile| used to retrieve the database 255 // to which user's ONC defined certificates should be imported. 256 // It parses and imports |onc_blob|. 257 void ImportONCFileToNSSDB(const std::string& onc_blob, 258 const std::string& passcode, 259 net::NSSCertDatabase* nssdb); 260 261 // Called back by the CertificateImporter when a certificate import finished. 262 // |previous_error| contains earlier errors during this import. 263 void OnCertificatesImported( 264 const std::string& previous_error, 265 bool success, 266 const net::CertificateList& onc_trusted_certificates); 267 #endif 268 269 private: 270 class IOThreadImpl; 271 272 #if defined(OS_CHROMEOS) 273 // Class that is used for getting network related ChromeOS logs. 274 // Logs are fetched from ChromeOS libcros on user request, and only when we 275 // don't yet have a copy of logs. If a copy is present, we send back data from 276 // it, else we save request and answer to it when we get logs from libcros. 277 // If needed, we also send request for system logs to libcros. 278 // Logs refresh has to be done explicitly, by deleting old logs and then 279 // loading them again. 280 class SystemLogsGetter { 281 public: 282 SystemLogsGetter(NetInternalsMessageHandler* handler, 283 chromeos::system::SyslogsProvider* syslogs_provider); 284 ~SystemLogsGetter(); 285 286 // Deletes logs copy we currently have, and resets logs_requested and 287 // logs_received flags. 288 void DeleteSystemLogs(); 289 // Starts log fetching. If logs copy is present, requested logs are sent 290 // back. 291 // If syslogs load request hasn't been sent to libcros yet, we do that now, 292 // and postpone sending response. 293 // Request data is specified by args: 294 // $1 : key of the log we are interested in. 295 // $2 : string used to identify request. 296 void RequestSystemLog(const base::ListValue* args); 297 // Requests logs from libcros, but only if we don't have a copy. 298 void LoadSystemLogs(); 299 // Processes callback from libcros containing system logs. Postponed 300 // request responses are sent. 301 void OnSystemLogsLoaded(chromeos::system::LogDictionaryType* sys_info, 302 std::string* ignored_content); 303 304 private: 305 // Struct we save postponed log request in. 306 struct SystemLogRequest { 307 std::string log_key; 308 std::string cell_id; 309 }; 310 311 // Processes request. 312 void SendLogs(const SystemLogRequest& request); 313 314 NetInternalsMessageHandler* handler_; 315 chromeos::system::SyslogsProvider* syslogs_provider_; 316 // List of postponed requests. 317 std::list<SystemLogRequest> requests_; 318 scoped_ptr<chromeos::system::LogDictionaryType> logs_; 319 bool logs_received_; 320 bool logs_requested_; 321 base::CancelableTaskTracker tracker_; 322 // Libcros request task ID. 323 base::CancelableTaskTracker::TaskId syslogs_task_id_; 324 }; 325 #endif // defined(OS_CHROMEOS) 326 327 // This is the "real" message handler, which lives on the IO thread. 328 scoped_refptr<IOThreadImpl> proxy_; 329 330 base::WeakPtr<prerender::PrerenderManager> prerender_manager_; 331 332 #if defined(OS_CHROMEOS) 333 // Class that handles getting and filtering system logs. 334 scoped_ptr<SystemLogsGetter> syslogs_getter_; 335 #endif 336 337 DISALLOW_COPY_AND_ASSIGN(NetInternalsMessageHandler); 338 }; 339 340 // This class is the "real" message handler. It is allocated and destroyed on 341 // the UI thread. With the exception of OnAddEntry, OnWebUIDeleted, and 342 // SendJavascriptCommand, its methods are all expected to be called from the IO 343 // thread. OnAddEntry and SendJavascriptCommand can be called from any thread, 344 // and OnWebUIDeleted can only be called from the UI thread. 345 class NetInternalsMessageHandler::IOThreadImpl 346 : public base::RefCountedThreadSafe< 347 NetInternalsMessageHandler::IOThreadImpl, 348 BrowserThread::DeleteOnUIThread>, 349 public net::NetLog::ThreadSafeObserver, 350 public ConnectionTester::Delegate { 351 public: 352 // Type for methods that can be used as MessageHandler callbacks. 353 typedef void (IOThreadImpl::*MessageHandler)(const base::ListValue*); 354 355 // Creates a proxy for |handler| that will live on the IO thread. 356 // |handler| is a weak pointer, since it is possible for the 357 // WebUIMessageHandler to be deleted on the UI thread while we were executing 358 // on the IO thread. |io_thread| is the global IOThread (it is passed in as 359 // an argument since we need to grab it from the UI thread). 360 IOThreadImpl( 361 const base::WeakPtr<NetInternalsMessageHandler>& handler, 362 IOThread* io_thread, 363 net::URLRequestContextGetter* main_context_getter); 364 365 // Called on UI thread just after creation, to add a ContextGetter to 366 // |context_getters_|. 367 void AddRequestContextGetter(net::URLRequestContextGetter* context_getter); 368 369 // Helper method to enable a callback that will be executed on the IO thread. 370 static void CallbackHelper(MessageHandler method, 371 scoped_refptr<IOThreadImpl> io_thread, 372 const base::ListValue* list); 373 374 // Called once the WebUI has been deleted (i.e. renderer went away), on the 375 // IO thread. 376 void Detach(); 377 378 // Called when the WebUI is deleted. Prevents calling Javascript functions 379 // afterwards. Called on UI thread. 380 void OnWebUIDeleted(); 381 382 //-------------------------------- 383 // Javascript message handlers: 384 //-------------------------------- 385 386 void OnRendererReady(const base::ListValue* list); 387 388 void OnGetProxySettings(const base::ListValue* list); 389 void OnReloadProxySettings(const base::ListValue* list); 390 void OnGetBadProxies(const base::ListValue* list); 391 void OnClearBadProxies(const base::ListValue* list); 392 void OnGetHostResolverInfo(const base::ListValue* list); 393 void OnClearHostResolverCache(const base::ListValue* list); 394 void OnEnableIPv6(const base::ListValue* list); 395 void OnStartConnectionTests(const base::ListValue* list); 396 void OnHSTSQuery(const base::ListValue* list); 397 void OnHSTSAdd(const base::ListValue* list); 398 void OnHSTSDelete(const base::ListValue* list); 399 void OnGetHttpCacheInfo(const base::ListValue* list); 400 void OnGetSocketPoolInfo(const base::ListValue* list); 401 void OnGetSessionNetworkStats(const base::ListValue* list); 402 void OnCloseIdleSockets(const base::ListValue* list); 403 void OnFlushSocketPools(const base::ListValue* list); 404 void OnGetSpdySessionInfo(const base::ListValue* list); 405 void OnGetSpdyStatus(const base::ListValue* list); 406 void OnGetSpdyAlternateProtocolMappings(const base::ListValue* list); 407 void OnGetQuicInfo(const base::ListValue* list); 408 #if defined(OS_WIN) 409 void OnGetServiceProviders(const base::ListValue* list); 410 #endif 411 void OnSetLogLevel(const base::ListValue* list); 412 413 // ChromeNetLog::ThreadSafeObserver implementation: 414 virtual void OnAddEntry(const net::NetLog::Entry& entry) OVERRIDE; 415 416 // ConnectionTester::Delegate implementation: 417 virtual void OnStartConnectionTestSuite() OVERRIDE; 418 virtual void OnStartConnectionTestExperiment( 419 const ConnectionTester::Experiment& experiment) OVERRIDE; 420 virtual void OnCompletedConnectionTestExperiment( 421 const ConnectionTester::Experiment& experiment, 422 int result) OVERRIDE; 423 virtual void OnCompletedConnectionTestSuite() OVERRIDE; 424 425 // Helper that calls g_browser.receive in the renderer, passing in |command| 426 // and |arg|. Takes ownership of |arg|. If the renderer is displaying a log 427 // file, the message will be ignored. Note that this can be called from any 428 // thread. 429 void SendJavascriptCommand(const std::string& command, base::Value* arg); 430 431 private: 432 friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>; 433 friend class base::DeleteHelper<IOThreadImpl>; 434 435 typedef std::list<scoped_refptr<net::URLRequestContextGetter> > 436 ContextGetterList; 437 438 virtual ~IOThreadImpl(); 439 440 // Adds |entry| to the queue of pending log entries to be sent to the page via 441 // Javascript. Must be called on the IO Thread. Also creates a delayed task 442 // that will call PostPendingEntries, if there isn't one already. 443 void AddEntryToQueue(base::Value* entry); 444 445 // Sends all pending entries to the page via Javascript, and clears the list 446 // of pending entries. Sending multiple entries at once results in a 447 // significant reduction of CPU usage when a lot of events are happening. 448 // Must be called on the IO Thread. 449 void PostPendingEntries(); 450 451 // Adds entries with the states of ongoing URL requests. 452 void PrePopulateEventList(); 453 454 net::URLRequestContext* GetMainContext() { 455 return main_context_getter_->GetURLRequestContext(); 456 } 457 458 // Pointer to the UI-thread message handler. Only access this from 459 // the UI thread. 460 base::WeakPtr<NetInternalsMessageHandler> handler_; 461 462 // The global IOThread, which contains the global NetLog to observer. 463 IOThread* io_thread_; 464 465 // The main URLRequestContextGetter for the tab's profile. 466 scoped_refptr<net::URLRequestContextGetter> main_context_getter_; 467 468 // Helper that runs the suite of connection tests. 469 scoped_ptr<ConnectionTester> connection_tester_; 470 471 // True if the Web UI has been deleted. This is used to prevent calling 472 // Javascript functions after the Web UI is destroyed. On refresh, the 473 // messages can end up being sent to the refreshed page, causing duplicate 474 // or partial entries. 475 // 476 // This is only read and written to on the UI thread. 477 bool was_webui_deleted_; 478 479 // Log entries that have yet to be passed along to Javascript page. Non-NULL 480 // when and only when there is a pending delayed task to call 481 // PostPendingEntries. Read and written to exclusively on the IO Thread. 482 scoped_ptr<base::ListValue> pending_entries_; 483 484 // Used for getting current status of URLRequests when net-internals is 485 // opened. |main_context_getter_| is automatically added on construction. 486 // Duplicates are allowed. 487 ContextGetterList context_getters_; 488 489 DISALLOW_COPY_AND_ASSIGN(IOThreadImpl); 490 }; 491 492 //////////////////////////////////////////////////////////////////////////////// 493 // 494 // NetInternalsMessageHandler 495 // 496 //////////////////////////////////////////////////////////////////////////////// 497 498 NetInternalsMessageHandler::NetInternalsMessageHandler() {} 499 500 NetInternalsMessageHandler::~NetInternalsMessageHandler() { 501 if (proxy_.get()) { 502 proxy_.get()->OnWebUIDeleted(); 503 // Notify the handler on the IO thread that the renderer is gone. 504 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 505 base::Bind(&IOThreadImpl::Detach, proxy_.get())); 506 } 507 } 508 509 void NetInternalsMessageHandler::RegisterMessages() { 510 DCHECK_CURRENTLY_ON(BrowserThread::UI); 511 512 Profile* profile = Profile::FromWebUI(web_ui()); 513 514 proxy_ = new IOThreadImpl(this->AsWeakPtr(), g_browser_process->io_thread(), 515 profile->GetRequestContext()); 516 proxy_->AddRequestContextGetter(profile->GetMediaRequestContext()); 517 proxy_->AddRequestContextGetter(profile->GetRequestContextForExtensions()); 518 #if defined(OS_CHROMEOS) 519 syslogs_getter_.reset(new SystemLogsGetter(this, 520 chromeos::system::SyslogsProvider::GetInstance())); 521 #endif 522 523 prerender::PrerenderManager* prerender_manager = 524 prerender::PrerenderManagerFactory::GetForProfile(profile); 525 if (prerender_manager) { 526 prerender_manager_ = prerender_manager->AsWeakPtr(); 527 } else { 528 prerender_manager_ = base::WeakPtr<prerender::PrerenderManager>(); 529 } 530 531 web_ui()->RegisterMessageCallback( 532 "notifyReady", 533 base::Bind(&NetInternalsMessageHandler::OnRendererReady, 534 base::Unretained(this))); 535 web_ui()->RegisterMessageCallback( 536 "getProxySettings", 537 base::Bind(&IOThreadImpl::CallbackHelper, 538 &IOThreadImpl::OnGetProxySettings, proxy_)); 539 web_ui()->RegisterMessageCallback( 540 "reloadProxySettings", 541 base::Bind(&IOThreadImpl::CallbackHelper, 542 &IOThreadImpl::OnReloadProxySettings, proxy_)); 543 web_ui()->RegisterMessageCallback( 544 "getBadProxies", 545 base::Bind(&IOThreadImpl::CallbackHelper, 546 &IOThreadImpl::OnGetBadProxies, proxy_)); 547 web_ui()->RegisterMessageCallback( 548 "clearBadProxies", 549 base::Bind(&IOThreadImpl::CallbackHelper, 550 &IOThreadImpl::OnClearBadProxies, proxy_)); 551 web_ui()->RegisterMessageCallback( 552 "getHostResolverInfo", 553 base::Bind(&IOThreadImpl::CallbackHelper, 554 &IOThreadImpl::OnGetHostResolverInfo, proxy_)); 555 web_ui()->RegisterMessageCallback( 556 "clearHostResolverCache", 557 base::Bind(&IOThreadImpl::CallbackHelper, 558 &IOThreadImpl::OnClearHostResolverCache, proxy_)); 559 web_ui()->RegisterMessageCallback( 560 "enableIPv6", 561 base::Bind(&IOThreadImpl::CallbackHelper, 562 &IOThreadImpl::OnEnableIPv6, proxy_)); 563 web_ui()->RegisterMessageCallback( 564 "startConnectionTests", 565 base::Bind(&IOThreadImpl::CallbackHelper, 566 &IOThreadImpl::OnStartConnectionTests, proxy_)); 567 web_ui()->RegisterMessageCallback( 568 "hstsQuery", 569 base::Bind(&IOThreadImpl::CallbackHelper, 570 &IOThreadImpl::OnHSTSQuery, proxy_)); 571 web_ui()->RegisterMessageCallback( 572 "hstsAdd", 573 base::Bind(&IOThreadImpl::CallbackHelper, 574 &IOThreadImpl::OnHSTSAdd, proxy_)); 575 web_ui()->RegisterMessageCallback( 576 "hstsDelete", 577 base::Bind(&IOThreadImpl::CallbackHelper, 578 &IOThreadImpl::OnHSTSDelete, proxy_)); 579 web_ui()->RegisterMessageCallback( 580 "getHttpCacheInfo", 581 base::Bind(&IOThreadImpl::CallbackHelper, 582 &IOThreadImpl::OnGetHttpCacheInfo, proxy_)); 583 web_ui()->RegisterMessageCallback( 584 "getSocketPoolInfo", 585 base::Bind(&IOThreadImpl::CallbackHelper, 586 &IOThreadImpl::OnGetSocketPoolInfo, proxy_)); 587 web_ui()->RegisterMessageCallback( 588 "getSessionNetworkStats", 589 base::Bind(&IOThreadImpl::CallbackHelper, 590 &IOThreadImpl::OnGetSessionNetworkStats, proxy_)); 591 web_ui()->RegisterMessageCallback( 592 "closeIdleSockets", 593 base::Bind(&IOThreadImpl::CallbackHelper, 594 &IOThreadImpl::OnCloseIdleSockets, proxy_)); 595 web_ui()->RegisterMessageCallback( 596 "flushSocketPools", 597 base::Bind(&IOThreadImpl::CallbackHelper, 598 &IOThreadImpl::OnFlushSocketPools, proxy_)); 599 web_ui()->RegisterMessageCallback( 600 "getSpdySessionInfo", 601 base::Bind(&IOThreadImpl::CallbackHelper, 602 &IOThreadImpl::OnGetSpdySessionInfo, proxy_)); 603 web_ui()->RegisterMessageCallback( 604 "getSpdyStatus", 605 base::Bind(&IOThreadImpl::CallbackHelper, 606 &IOThreadImpl::OnGetSpdyStatus, proxy_)); 607 web_ui()->RegisterMessageCallback( 608 "getSpdyAlternateProtocolMappings", 609 base::Bind(&IOThreadImpl::CallbackHelper, 610 &IOThreadImpl::OnGetSpdyAlternateProtocolMappings, proxy_)); 611 web_ui()->RegisterMessageCallback( 612 "getQuicInfo", 613 base::Bind(&IOThreadImpl::CallbackHelper, 614 &IOThreadImpl::OnGetQuicInfo, proxy_)); 615 #if defined(OS_WIN) 616 web_ui()->RegisterMessageCallback( 617 "getServiceProviders", 618 base::Bind(&IOThreadImpl::CallbackHelper, 619 &IOThreadImpl::OnGetServiceProviders, proxy_)); 620 #endif 621 622 web_ui()->RegisterMessageCallback( 623 "setLogLevel", 624 base::Bind(&IOThreadImpl::CallbackHelper, 625 &IOThreadImpl::OnSetLogLevel, proxy_)); 626 web_ui()->RegisterMessageCallback( 627 "clearBrowserCache", 628 base::Bind(&NetInternalsMessageHandler::OnClearBrowserCache, 629 base::Unretained(this))); 630 web_ui()->RegisterMessageCallback( 631 "getPrerenderInfo", 632 base::Bind(&NetInternalsMessageHandler::OnGetPrerenderInfo, 633 base::Unretained(this))); 634 web_ui()->RegisterMessageCallback( 635 "getHistoricNetworkStats", 636 base::Bind(&NetInternalsMessageHandler::OnGetHistoricNetworkStats, 637 base::Unretained(this))); 638 web_ui()->RegisterMessageCallback( 639 "getExtensionInfo", 640 base::Bind(&NetInternalsMessageHandler::OnGetExtensionInfo, 641 base::Unretained(this))); 642 #if defined(OS_CHROMEOS) 643 web_ui()->RegisterMessageCallback( 644 "refreshSystemLogs", 645 base::Bind(&NetInternalsMessageHandler::OnRefreshSystemLogs, 646 base::Unretained(this))); 647 web_ui()->RegisterMessageCallback( 648 "getSystemLog", 649 base::Bind(&NetInternalsMessageHandler::OnGetSystemLog, 650 base::Unretained(this))); 651 web_ui()->RegisterMessageCallback( 652 "importONCFile", 653 base::Bind(&NetInternalsMessageHandler::OnImportONCFile, 654 base::Unretained(this))); 655 web_ui()->RegisterMessageCallback( 656 "storeDebugLogs", 657 base::Bind(&NetInternalsMessageHandler::OnStoreDebugLogs, 658 base::Unretained(this))); 659 web_ui()->RegisterMessageCallback( 660 "setNetworkDebugMode", 661 base::Bind(&NetInternalsMessageHandler::OnSetNetworkDebugMode, 662 base::Unretained(this))); 663 #endif 664 } 665 666 void NetInternalsMessageHandler::SendJavascriptCommand( 667 const std::string& command, 668 base::Value* arg) { 669 scoped_ptr<base::Value> command_value(new base::StringValue(command)); 670 scoped_ptr<base::Value> value(arg); 671 DCHECK_CURRENTLY_ON(BrowserThread::UI); 672 if (value.get()) { 673 web_ui()->CallJavascriptFunction("g_browser.receive", 674 *command_value.get(), 675 *value.get()); 676 } else { 677 web_ui()->CallJavascriptFunction("g_browser.receive", 678 *command_value.get()); 679 } 680 } 681 682 void NetInternalsMessageHandler::OnRendererReady(const base::ListValue* list) { 683 IOThreadImpl::CallbackHelper(&IOThreadImpl::OnRendererReady, proxy_, list); 684 } 685 686 void NetInternalsMessageHandler::OnClearBrowserCache( 687 const base::ListValue* list) { 688 BrowsingDataRemover* remover = BrowsingDataRemover::CreateForUnboundedRange( 689 Profile::FromWebUI(web_ui())); 690 remover->Remove(BrowsingDataRemover::REMOVE_CACHE, 691 BrowsingDataHelper::UNPROTECTED_WEB); 692 // BrowsingDataRemover deletes itself. 693 } 694 695 void NetInternalsMessageHandler::OnGetPrerenderInfo( 696 const base::ListValue* list) { 697 DCHECK_CURRENTLY_ON(BrowserThread::UI); 698 699 base::DictionaryValue* value = NULL; 700 prerender::PrerenderManager* prerender_manager = prerender_manager_.get(); 701 if (!prerender_manager) { 702 value = new base::DictionaryValue(); 703 value->SetBoolean("enabled", false); 704 value->SetBoolean("omnibox_enabled", false); 705 } else { 706 value = prerender_manager->GetAsValue(); 707 } 708 SendJavascriptCommand("receivedPrerenderInfo", value); 709 } 710 711 void NetInternalsMessageHandler::OnGetHistoricNetworkStats( 712 const base::ListValue* list) { 713 DCHECK_CURRENTLY_ON(BrowserThread::UI); 714 base::Value* historic_network_info = 715 ChromeNetworkDelegate::HistoricNetworkStatsInfoToValue(); 716 SendJavascriptCommand("receivedHistoricNetworkStats", historic_network_info); 717 } 718 719 void NetInternalsMessageHandler::OnGetExtensionInfo( 720 const base::ListValue* list) { 721 DCHECK_CURRENTLY_ON(BrowserThread::UI); 722 base::ListValue* extension_list = new base::ListValue(); 723 #if defined(ENABLE_EXTENSIONS) 724 Profile* profile = Profile::FromWebUI(web_ui()); 725 extensions::ExtensionSystem* extension_system = 726 extensions::ExtensionSystem::Get(profile); 727 if (extension_system) { 728 ExtensionService* extension_service = extension_system->extension_service(); 729 if (extension_service) { 730 scoped_ptr<const extensions::ExtensionSet> extensions( 731 extensions::ExtensionRegistry::Get(profile) 732 ->GenerateInstalledExtensionsSet()); 733 for (extensions::ExtensionSet::const_iterator it = extensions->begin(); 734 it != extensions->end(); ++it) { 735 base::DictionaryValue* extension_info = new base::DictionaryValue(); 736 bool enabled = extension_service->IsExtensionEnabled((*it)->id()); 737 extensions::GetExtensionBasicInfo(it->get(), enabled, extension_info); 738 extension_list->Append(extension_info); 739 } 740 } 741 } 742 #endif 743 SendJavascriptCommand("receivedExtensionInfo", extension_list); 744 } 745 746 #if defined(OS_CHROMEOS) 747 //////////////////////////////////////////////////////////////////////////////// 748 // 749 // NetInternalsMessageHandler::SystemLogsGetter 750 // 751 //////////////////////////////////////////////////////////////////////////////// 752 753 NetInternalsMessageHandler::SystemLogsGetter::SystemLogsGetter( 754 NetInternalsMessageHandler* handler, 755 chromeos::system::SyslogsProvider* syslogs_provider) 756 : handler_(handler), 757 syslogs_provider_(syslogs_provider), 758 logs_received_(false), 759 logs_requested_(false) { 760 if (!syslogs_provider_) 761 LOG(ERROR) << "System access library not loaded"; 762 } 763 764 NetInternalsMessageHandler::SystemLogsGetter::~SystemLogsGetter() { 765 DeleteSystemLogs(); 766 } 767 768 void NetInternalsMessageHandler::SystemLogsGetter::DeleteSystemLogs() { 769 if (syslogs_provider_ && logs_requested_ && !logs_received_) { 770 tracker_.TryCancel(syslogs_task_id_); 771 } 772 logs_requested_ = false; 773 logs_received_ = false; 774 logs_.reset(); 775 } 776 777 void NetInternalsMessageHandler::SystemLogsGetter::RequestSystemLog( 778 const base::ListValue* args) { 779 if (!logs_requested_) { 780 DCHECK(!logs_received_); 781 LoadSystemLogs(); 782 } 783 SystemLogRequest log_request; 784 args->GetString(0, &log_request.log_key); 785 args->GetString(1, &log_request.cell_id); 786 787 if (logs_received_) { 788 SendLogs(log_request); 789 } else { 790 requests_.push_back(log_request); 791 } 792 } 793 794 void NetInternalsMessageHandler::SystemLogsGetter::LoadSystemLogs() { 795 if (logs_requested_ || !syslogs_provider_) 796 return; 797 logs_requested_ = true; 798 syslogs_task_id_ = syslogs_provider_->RequestSyslogs( 799 false, // compress logs. 800 chromeos::system::SyslogsProvider::SYSLOGS_NETWORK, 801 base::Bind( 802 &NetInternalsMessageHandler::SystemLogsGetter::OnSystemLogsLoaded, 803 base::Unretained(this)), 804 &tracker_); 805 } 806 807 void NetInternalsMessageHandler::SystemLogsGetter::OnSystemLogsLoaded( 808 chromeos::system::LogDictionaryType* sys_info, 809 std::string* ignored_content) { 810 DCHECK(!ignored_content); 811 logs_.reset(sys_info); 812 logs_received_ = true; 813 for (std::list<SystemLogRequest>::iterator request_it = requests_.begin(); 814 request_it != requests_.end(); 815 ++request_it) { 816 SendLogs(*request_it); 817 } 818 requests_.clear(); 819 } 820 821 void NetInternalsMessageHandler::SystemLogsGetter::SendLogs( 822 const SystemLogRequest& request) { 823 base::DictionaryValue* result = new base::DictionaryValue(); 824 chromeos::system::LogDictionaryType::iterator log_it = 825 logs_->find(request.log_key); 826 if (log_it != logs_->end()) { 827 if (!log_it->second.empty()) { 828 result->SetString("log", log_it->second); 829 } else { 830 result->SetString("log", "<no relevant lines found>"); 831 } 832 } else { 833 result->SetString("log", "<invalid log name>"); 834 } 835 result->SetString("cellId", request.cell_id); 836 837 handler_->SendJavascriptCommand("getSystemLogCallback", result); 838 } 839 #endif // defined(OS_CHROMEOS) 840 841 //////////////////////////////////////////////////////////////////////////////// 842 // 843 // NetInternalsMessageHandler::IOThreadImpl 844 // 845 //////////////////////////////////////////////////////////////////////////////// 846 847 NetInternalsMessageHandler::IOThreadImpl::IOThreadImpl( 848 const base::WeakPtr<NetInternalsMessageHandler>& handler, 849 IOThread* io_thread, 850 net::URLRequestContextGetter* main_context_getter) 851 : handler_(handler), 852 io_thread_(io_thread), 853 main_context_getter_(main_context_getter), 854 was_webui_deleted_(false) { 855 DCHECK_CURRENTLY_ON(BrowserThread::UI); 856 AddRequestContextGetter(main_context_getter); 857 } 858 859 NetInternalsMessageHandler::IOThreadImpl::~IOThreadImpl() { 860 DCHECK_CURRENTLY_ON(BrowserThread::UI); 861 } 862 863 void NetInternalsMessageHandler::IOThreadImpl::AddRequestContextGetter( 864 net::URLRequestContextGetter* context_getter) { 865 DCHECK_CURRENTLY_ON(BrowserThread::UI); 866 context_getters_.push_back(context_getter); 867 } 868 869 void NetInternalsMessageHandler::IOThreadImpl::CallbackHelper( 870 MessageHandler method, 871 scoped_refptr<IOThreadImpl> io_thread, 872 const base::ListValue* list) { 873 DCHECK_CURRENTLY_ON(BrowserThread::UI); 874 875 // We need to make a copy of the value in order to pass it over to the IO 876 // thread. |list_copy| will be deleted when the task is destroyed. The called 877 // |method| cannot take ownership of |list_copy|. 878 base::ListValue* list_copy = 879 (list && list->GetSize()) ? list->DeepCopy() : NULL; 880 881 BrowserThread::PostTask( 882 BrowserThread::IO, FROM_HERE, 883 base::Bind(method, io_thread, base::Owned(list_copy))); 884 } 885 886 void NetInternalsMessageHandler::IOThreadImpl::Detach() { 887 DCHECK_CURRENTLY_ON(BrowserThread::IO); 888 // Unregister with network stack to observe events. 889 if (net_log()) 890 net_log()->RemoveThreadSafeObserver(this); 891 892 // Cancel any in-progress connection tests. 893 connection_tester_.reset(); 894 } 895 896 void NetInternalsMessageHandler::IOThreadImpl::OnWebUIDeleted() { 897 DCHECK_CURRENTLY_ON(BrowserThread::UI); 898 was_webui_deleted_ = true; 899 } 900 901 void NetInternalsMessageHandler::IOThreadImpl::OnRendererReady( 902 const base::ListValue* list) { 903 DCHECK_CURRENTLY_ON(BrowserThread::IO); 904 905 // If we have any pending entries, go ahead and get rid of them, so they won't 906 // appear before the REQUEST_ALIVE events we add for currently active 907 // URLRequests. 908 PostPendingEntries(); 909 910 SendJavascriptCommand("receivedConstants", NetInternalsUI::GetConstants()); 911 912 // Add entries for ongoing URL requests. 913 PrePopulateEventList(); 914 915 if (!net_log()) { 916 // Register with network stack to observe events. 917 io_thread_->net_log()->AddThreadSafeObserver(this, 918 net::NetLog::LOG_ALL_BUT_BYTES); 919 } 920 } 921 922 void NetInternalsMessageHandler::IOThreadImpl::OnGetProxySettings( 923 const base::ListValue* list) { 924 DCHECK(!list); 925 net::ProxyService* proxy_service = GetMainContext()->proxy_service(); 926 927 base::DictionaryValue* dict = new base::DictionaryValue(); 928 if (proxy_service->fetched_config().is_valid()) 929 dict->Set("original", proxy_service->fetched_config().ToValue()); 930 if (proxy_service->config().is_valid()) 931 dict->Set("effective", proxy_service->config().ToValue()); 932 933 SendJavascriptCommand("receivedProxySettings", dict); 934 } 935 936 void NetInternalsMessageHandler::IOThreadImpl::OnReloadProxySettings( 937 const base::ListValue* list) { 938 DCHECK(!list); 939 GetMainContext()->proxy_service()->ForceReloadProxyConfig(); 940 941 // Cause the renderer to be notified of the new values. 942 OnGetProxySettings(NULL); 943 } 944 945 void NetInternalsMessageHandler::IOThreadImpl::OnGetBadProxies( 946 const base::ListValue* list) { 947 DCHECK(!list); 948 949 const net::ProxyRetryInfoMap& bad_proxies_map = 950 GetMainContext()->proxy_service()->proxy_retry_info(); 951 952 base::ListValue* dict_list = new base::ListValue(); 953 954 for (net::ProxyRetryInfoMap::const_iterator it = bad_proxies_map.begin(); 955 it != bad_proxies_map.end(); ++it) { 956 const std::string& proxy_uri = it->first; 957 const net::ProxyRetryInfo& retry_info = it->second; 958 959 base::DictionaryValue* dict = new base::DictionaryValue(); 960 dict->SetString("proxy_uri", proxy_uri); 961 dict->SetString("bad_until", 962 net::NetLog::TickCountToString(retry_info.bad_until)); 963 964 dict_list->Append(dict); 965 } 966 967 SendJavascriptCommand("receivedBadProxies", dict_list); 968 } 969 970 void NetInternalsMessageHandler::IOThreadImpl::OnClearBadProxies( 971 const base::ListValue* list) { 972 DCHECK(!list); 973 GetMainContext()->proxy_service()->ClearBadProxiesCache(); 974 975 // Cause the renderer to be notified of the new values. 976 OnGetBadProxies(NULL); 977 } 978 979 void NetInternalsMessageHandler::IOThreadImpl::OnGetHostResolverInfo( 980 const base::ListValue* list) { 981 DCHECK(!list); 982 net::URLRequestContext* context = GetMainContext(); 983 net::HostCache* cache = GetHostResolverCache(context); 984 985 if (!cache) { 986 SendJavascriptCommand("receivedHostResolverInfo", NULL); 987 return; 988 } 989 990 base::DictionaryValue* dict = new base::DictionaryValue(); 991 992 base::Value* dns_config = context->host_resolver()->GetDnsConfigAsValue(); 993 if (dns_config) 994 dict->Set("dns_config", dns_config); 995 996 dict->SetInteger( 997 "default_address_family", 998 static_cast<int>(context->host_resolver()->GetDefaultAddressFamily())); 999 1000 base::DictionaryValue* cache_info_dict = new base::DictionaryValue(); 1001 1002 cache_info_dict->SetInteger( 1003 "capacity", 1004 static_cast<int>(cache->max_entries())); 1005 1006 base::ListValue* entry_list = new base::ListValue(); 1007 1008 net::HostCache::EntryMap::Iterator it(cache->entries()); 1009 for (; it.HasNext(); it.Advance()) { 1010 const net::HostCache::Key& key = it.key(); 1011 const net::HostCache::Entry& entry = it.value(); 1012 1013 base::DictionaryValue* entry_dict = new base::DictionaryValue(); 1014 1015 entry_dict->SetString("hostname", key.hostname); 1016 entry_dict->SetInteger("address_family", 1017 static_cast<int>(key.address_family)); 1018 entry_dict->SetString("expiration", 1019 net::NetLog::TickCountToString(it.expiration())); 1020 1021 if (entry.error != net::OK) { 1022 entry_dict->SetInteger("error", entry.error); 1023 } else { 1024 // Append all of the resolved addresses. 1025 base::ListValue* address_list = new base::ListValue(); 1026 for (size_t i = 0; i < entry.addrlist.size(); ++i) { 1027 address_list->AppendString(entry.addrlist[i].ToStringWithoutPort()); 1028 } 1029 entry_dict->Set("addresses", address_list); 1030 } 1031 1032 entry_list->Append(entry_dict); 1033 } 1034 1035 cache_info_dict->Set("entries", entry_list); 1036 dict->Set("cache", cache_info_dict); 1037 1038 SendJavascriptCommand("receivedHostResolverInfo", dict); 1039 } 1040 1041 void NetInternalsMessageHandler::IOThreadImpl::OnClearHostResolverCache( 1042 const base::ListValue* list) { 1043 DCHECK(!list); 1044 net::HostCache* cache = GetHostResolverCache(GetMainContext()); 1045 1046 if (cache) 1047 cache->clear(); 1048 1049 // Cause the renderer to be notified of the new values. 1050 OnGetHostResolverInfo(NULL); 1051 } 1052 1053 void NetInternalsMessageHandler::IOThreadImpl::OnEnableIPv6( 1054 const base::ListValue* list) { 1055 DCHECK(!list); 1056 net::HostResolver* host_resolver = GetMainContext()->host_resolver(); 1057 1058 host_resolver->SetDefaultAddressFamily(net::ADDRESS_FAMILY_UNSPECIFIED); 1059 1060 // Cause the renderer to be notified of the new value. 1061 OnGetHostResolverInfo(NULL); 1062 } 1063 1064 void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTests( 1065 const base::ListValue* list) { 1066 // |value| should be: [<URL to test>]. 1067 base::string16 url_str; 1068 CHECK(list->GetString(0, &url_str)); 1069 1070 // Try to fix-up the user provided URL into something valid. 1071 // For example, turn "www.google.com" into "http://www.google.com". 1072 GURL url(url_fixer::FixupURL(base::UTF16ToUTF8(url_str), std::string())); 1073 1074 connection_tester_.reset(new ConnectionTester( 1075 this, 1076 io_thread_->globals()->proxy_script_fetcher_context.get(), 1077 net_log())); 1078 connection_tester_->RunAllTests(url); 1079 } 1080 1081 void NetInternalsMessageHandler::IOThreadImpl::OnHSTSQuery( 1082 const base::ListValue* list) { 1083 // |list| should be: [<domain to query>]. 1084 std::string domain; 1085 CHECK(list->GetString(0, &domain)); 1086 base::DictionaryValue* result = new base::DictionaryValue(); 1087 1088 if (!base::IsStringASCII(domain)) { 1089 result->SetString("error", "non-ASCII domain name"); 1090 } else { 1091 net::TransportSecurityState* transport_security_state = 1092 GetMainContext()->transport_security_state(); 1093 if (!transport_security_state) { 1094 result->SetString("error", "no TransportSecurityState active"); 1095 } else { 1096 net::TransportSecurityState::DomainState static_state; 1097 const bool found_static = transport_security_state->GetStaticDomainState( 1098 domain, &static_state); 1099 if (found_static) { 1100 result->SetBoolean("has_static_sts", 1101 found_static && static_state.ShouldUpgradeToSSL()); 1102 result->SetInteger("static_upgrade_mode", 1103 static_cast<int>(static_state.sts.upgrade_mode)); 1104 result->SetBoolean("static_sts_include_subdomains", 1105 static_state.sts.include_subdomains); 1106 result->SetDouble("static_sts_observed", 1107 static_state.sts.last_observed.ToDoubleT()); 1108 result->SetDouble("static_sts_expiry", 1109 static_state.sts.expiry.ToDoubleT()); 1110 result->SetBoolean("has_static_pkp", 1111 found_static && static_state.HasPublicKeyPins()); 1112 result->SetBoolean("static_pkp_include_subdomains", 1113 static_state.pkp.include_subdomains); 1114 result->SetDouble("static_pkp_observed", 1115 static_state.pkp.last_observed.ToDoubleT()); 1116 result->SetDouble("static_pkp_expiry", 1117 static_state.pkp.expiry.ToDoubleT()); 1118 result->SetString("static_spki_hashes", 1119 HashesToBase64String(static_state.pkp.spki_hashes)); 1120 } 1121 1122 net::TransportSecurityState::DomainState dynamic_state; 1123 const bool found_dynamic = 1124 transport_security_state->GetDynamicDomainState(domain, 1125 &dynamic_state); 1126 if (found_dynamic) { 1127 result->SetInteger("dynamic_upgrade_mode", 1128 static_cast<int>(dynamic_state.sts.upgrade_mode)); 1129 result->SetBoolean("dynamic_sts_include_subdomains", 1130 dynamic_state.sts.include_subdomains); 1131 result->SetBoolean("dynamic_pkp_include_subdomains", 1132 dynamic_state.pkp.include_subdomains); 1133 result->SetDouble("dynamic_sts_observed", 1134 dynamic_state.sts.last_observed.ToDoubleT()); 1135 result->SetDouble("dynamic_pkp_observed", 1136 dynamic_state.pkp.last_observed.ToDoubleT()); 1137 result->SetDouble("dynamic_sts_expiry", 1138 dynamic_state.sts.expiry.ToDoubleT()); 1139 result->SetDouble("dynamic_pkp_expiry", 1140 dynamic_state.pkp.expiry.ToDoubleT()); 1141 result->SetString("dynamic_spki_hashes", 1142 HashesToBase64String(dynamic_state.pkp.spki_hashes)); 1143 } 1144 1145 result->SetBoolean("result", found_static || found_dynamic); 1146 if (found_static) { 1147 result->SetString("domain", static_state.domain); 1148 } else if (found_dynamic) { 1149 result->SetString("domain", dynamic_state.domain); 1150 } else { 1151 result->SetString("domain", domain); 1152 } 1153 } 1154 } 1155 1156 SendJavascriptCommand("receivedHSTSResult", result); 1157 } 1158 1159 void NetInternalsMessageHandler::IOThreadImpl::OnHSTSAdd( 1160 const base::ListValue* list) { 1161 // |list| should be: [<domain to query>, <STS include subdomains>, <PKP 1162 // include subdomains>, <key pins>]. 1163 std::string domain; 1164 CHECK(list->GetString(0, &domain)); 1165 if (!base::IsStringASCII(domain)) { 1166 // Silently fail. The user will get a helpful error if they query for the 1167 // name. 1168 return; 1169 } 1170 bool sts_include_subdomains; 1171 CHECK(list->GetBoolean(1, &sts_include_subdomains)); 1172 bool pkp_include_subdomains; 1173 CHECK(list->GetBoolean(2, &pkp_include_subdomains)); 1174 std::string hashes_str; 1175 CHECK(list->GetString(3, &hashes_str)); 1176 1177 net::TransportSecurityState* transport_security_state = 1178 GetMainContext()->transport_security_state(); 1179 if (!transport_security_state) 1180 return; 1181 1182 base::Time expiry = base::Time::Now() + base::TimeDelta::FromDays(1000); 1183 net::HashValueVector hashes; 1184 if (!hashes_str.empty()) { 1185 if (!Base64StringToHashes(hashes_str, &hashes)) 1186 return; 1187 } 1188 1189 transport_security_state->AddHSTS(domain, expiry, sts_include_subdomains); 1190 transport_security_state->AddHPKP(domain, expiry, pkp_include_subdomains, 1191 hashes); 1192 } 1193 1194 void NetInternalsMessageHandler::IOThreadImpl::OnHSTSDelete( 1195 const base::ListValue* list) { 1196 // |list| should be: [<domain to query>]. 1197 std::string domain; 1198 CHECK(list->GetString(0, &domain)); 1199 if (!base::IsStringASCII(domain)) { 1200 // There cannot be a unicode entry in the HSTS set. 1201 return; 1202 } 1203 net::TransportSecurityState* transport_security_state = 1204 GetMainContext()->transport_security_state(); 1205 if (!transport_security_state) 1206 return; 1207 1208 transport_security_state->DeleteDynamicDataForHost(domain); 1209 } 1210 1211 void NetInternalsMessageHandler::IOThreadImpl::OnGetHttpCacheInfo( 1212 const base::ListValue* list) { 1213 DCHECK(!list); 1214 base::DictionaryValue* info_dict = new base::DictionaryValue(); 1215 base::DictionaryValue* stats_dict = new base::DictionaryValue(); 1216 1217 disk_cache::Backend* disk_cache = GetDiskCacheBackend(GetMainContext()); 1218 1219 if (disk_cache) { 1220 // Extract the statistics key/value pairs from the backend. 1221 base::StringPairs stats; 1222 disk_cache->GetStats(&stats); 1223 for (size_t i = 0; i < stats.size(); ++i) { 1224 stats_dict->SetStringWithoutPathExpansion( 1225 stats[i].first, stats[i].second); 1226 } 1227 } 1228 1229 info_dict->Set("stats", stats_dict); 1230 1231 SendJavascriptCommand("receivedHttpCacheInfo", info_dict); 1232 } 1233 1234 void NetInternalsMessageHandler::IOThreadImpl::OnGetSocketPoolInfo( 1235 const base::ListValue* list) { 1236 DCHECK(!list); 1237 net::HttpNetworkSession* http_network_session = 1238 GetHttpNetworkSession(GetMainContext()); 1239 1240 base::Value* socket_pool_info = NULL; 1241 if (http_network_session) 1242 socket_pool_info = http_network_session->SocketPoolInfoToValue(); 1243 1244 SendJavascriptCommand("receivedSocketPoolInfo", socket_pool_info); 1245 } 1246 1247 void NetInternalsMessageHandler::IOThreadImpl::OnGetSessionNetworkStats( 1248 const base::ListValue* list) { 1249 DCHECK(!list); 1250 net::HttpNetworkSession* http_network_session = 1251 GetHttpNetworkSession(main_context_getter_->GetURLRequestContext()); 1252 1253 base::Value* network_info = NULL; 1254 if (http_network_session) { 1255 ChromeNetworkDelegate* net_delegate = 1256 static_cast<ChromeNetworkDelegate*>( 1257 http_network_session->network_delegate()); 1258 if (net_delegate) { 1259 network_info = net_delegate->SessionNetworkStatsInfoToValue(); 1260 } 1261 } 1262 SendJavascriptCommand("receivedSessionNetworkStats", network_info); 1263 } 1264 1265 void NetInternalsMessageHandler::IOThreadImpl::OnFlushSocketPools( 1266 const base::ListValue* list) { 1267 DCHECK(!list); 1268 net::HttpNetworkSession* http_network_session = 1269 GetHttpNetworkSession(GetMainContext()); 1270 1271 if (http_network_session) 1272 http_network_session->CloseAllConnections(); 1273 } 1274 1275 void NetInternalsMessageHandler::IOThreadImpl::OnCloseIdleSockets( 1276 const base::ListValue* list) { 1277 DCHECK(!list); 1278 net::HttpNetworkSession* http_network_session = 1279 GetHttpNetworkSession(GetMainContext()); 1280 1281 if (http_network_session) 1282 http_network_session->CloseIdleConnections(); 1283 } 1284 1285 void NetInternalsMessageHandler::IOThreadImpl::OnGetSpdySessionInfo( 1286 const base::ListValue* list) { 1287 DCHECK(!list); 1288 net::HttpNetworkSession* http_network_session = 1289 GetHttpNetworkSession(GetMainContext()); 1290 1291 base::Value* spdy_info = http_network_session ? 1292 http_network_session->SpdySessionPoolInfoToValue() : NULL; 1293 SendJavascriptCommand("receivedSpdySessionInfo", spdy_info); 1294 } 1295 1296 void NetInternalsMessageHandler::IOThreadImpl::OnGetSpdyStatus( 1297 const base::ListValue* list) { 1298 DCHECK(!list); 1299 base::DictionaryValue* status_dict = new base::DictionaryValue(); 1300 1301 net::HttpNetworkSession* http_network_session = 1302 GetHttpNetworkSession(GetMainContext()); 1303 1304 status_dict->SetBoolean("spdy_enabled", 1305 net::HttpStreamFactory::spdy_enabled()); 1306 status_dict->SetBoolean( 1307 "use_alternate_protocols", 1308 http_network_session->params().use_alternate_protocols); 1309 status_dict->SetBoolean("force_spdy_over_ssl", 1310 http_network_session->params().force_spdy_over_ssl); 1311 status_dict->SetBoolean("force_spdy_always", 1312 http_network_session->params().force_spdy_always); 1313 1314 std::vector<std::string> next_protos; 1315 http_network_session->GetNextProtos(&next_protos); 1316 std::string next_protos_string = JoinString(next_protos, ','); 1317 status_dict->SetString("next_protos", next_protos_string); 1318 1319 SendJavascriptCommand("receivedSpdyStatus", status_dict); 1320 } 1321 1322 void 1323 NetInternalsMessageHandler::IOThreadImpl::OnGetSpdyAlternateProtocolMappings( 1324 const base::ListValue* list) { 1325 DCHECK(!list); 1326 base::ListValue* dict_list = new base::ListValue(); 1327 1328 const net::HttpServerProperties& http_server_properties = 1329 *GetMainContext()->http_server_properties(); 1330 1331 const net::AlternateProtocolMap& map = 1332 http_server_properties.alternate_protocol_map(); 1333 1334 for (net::AlternateProtocolMap::const_iterator it = map.begin(); 1335 it != map.end(); ++it) { 1336 base::DictionaryValue* dict = new base::DictionaryValue(); 1337 dict->SetString("host_port_pair", it->first.ToString()); 1338 dict->SetString("alternate_protocol", it->second.ToString()); 1339 dict_list->Append(dict); 1340 } 1341 1342 SendJavascriptCommand("receivedSpdyAlternateProtocolMappings", dict_list); 1343 } 1344 1345 void NetInternalsMessageHandler::IOThreadImpl::OnGetQuicInfo( 1346 const base::ListValue* list) { 1347 DCHECK(!list); 1348 net::HttpNetworkSession* http_network_session = 1349 GetHttpNetworkSession(GetMainContext()); 1350 1351 base::Value* quic_info = http_network_session ? 1352 http_network_session->QuicInfoToValue() : NULL; 1353 SendJavascriptCommand("receivedQuicInfo", quic_info); 1354 } 1355 1356 #if defined(OS_WIN) 1357 void NetInternalsMessageHandler::IOThreadImpl::OnGetServiceProviders( 1358 const base::ListValue* list) { 1359 DCHECK(!list); 1360 1361 base::DictionaryValue* service_providers = new base::DictionaryValue(); 1362 1363 WinsockLayeredServiceProviderList layered_providers; 1364 GetWinsockLayeredServiceProviders(&layered_providers); 1365 base::ListValue* layered_provider_list = new base::ListValue(); 1366 for (size_t i = 0; i < layered_providers.size(); ++i) { 1367 base::DictionaryValue* service_dict = new base::DictionaryValue(); 1368 service_dict->SetString("name", layered_providers[i].name); 1369 service_dict->SetInteger("version", layered_providers[i].version); 1370 service_dict->SetInteger("chain_length", layered_providers[i].chain_length); 1371 service_dict->SetInteger("socket_type", layered_providers[i].socket_type); 1372 service_dict->SetInteger("socket_protocol", 1373 layered_providers[i].socket_protocol); 1374 service_dict->SetString("path", layered_providers[i].path); 1375 1376 layered_provider_list->Append(service_dict); 1377 } 1378 service_providers->Set("service_providers", layered_provider_list); 1379 1380 WinsockNamespaceProviderList namespace_providers; 1381 GetWinsockNamespaceProviders(&namespace_providers); 1382 base::ListValue* namespace_list = new base::ListValue; 1383 for (size_t i = 0; i < namespace_providers.size(); ++i) { 1384 base::DictionaryValue* namespace_dict = new base::DictionaryValue(); 1385 namespace_dict->SetString("name", namespace_providers[i].name); 1386 namespace_dict->SetBoolean("active", namespace_providers[i].active); 1387 namespace_dict->SetInteger("version", namespace_providers[i].version); 1388 namespace_dict->SetInteger("type", namespace_providers[i].type); 1389 1390 namespace_list->Append(namespace_dict); 1391 } 1392 service_providers->Set("namespace_providers", namespace_list); 1393 1394 SendJavascriptCommand("receivedServiceProviders", service_providers); 1395 } 1396 #endif 1397 1398 #if defined(OS_CHROMEOS) 1399 void NetInternalsMessageHandler::OnRefreshSystemLogs( 1400 const base::ListValue* list) { 1401 DCHECK(!list); 1402 DCHECK(syslogs_getter_.get()); 1403 syslogs_getter_->DeleteSystemLogs(); 1404 syslogs_getter_->LoadSystemLogs(); 1405 } 1406 1407 void NetInternalsMessageHandler::OnGetSystemLog( 1408 const base::ListValue* list) { 1409 DCHECK(syslogs_getter_.get()); 1410 syslogs_getter_->RequestSystemLog(list); 1411 } 1412 1413 void NetInternalsMessageHandler::ImportONCFileToNSSDB( 1414 const std::string& onc_blob, 1415 const std::string& passcode, 1416 net::NSSCertDatabase* nssdb) { 1417 user_manager::User* user = chromeos::ProfileHelper::Get()->GetUserByProfile( 1418 Profile::FromWebUI(web_ui())); 1419 1420 if (!user) { 1421 std::string error = "User not found."; 1422 SendJavascriptCommand("receivedONCFileParse", new base::StringValue(error)); 1423 return; 1424 } 1425 1426 std::string error; 1427 onc::ONCSource onc_source = onc::ONC_SOURCE_USER_IMPORT; 1428 base::ListValue network_configs; 1429 base::DictionaryValue global_network_config; 1430 base::ListValue certificates; 1431 if (!chromeos::onc::ParseAndValidateOncForImport(onc_blob, 1432 onc_source, 1433 passcode, 1434 &network_configs, 1435 &global_network_config, 1436 &certificates)) { 1437 error = "Errors occurred during the ONC parsing. "; 1438 } 1439 1440 std::string network_error; 1441 chromeos::onc::ImportNetworksForUser(user, network_configs, &network_error); 1442 if (!network_error.empty()) 1443 error += network_error; 1444 1445 chromeos::onc::CertificateImporterImpl cert_importer( 1446 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO), nssdb); 1447 cert_importer.ImportCertificates( 1448 certificates, 1449 onc_source, 1450 base::Bind(&NetInternalsMessageHandler::OnCertificatesImported, 1451 AsWeakPtr(), 1452 error)); 1453 } 1454 1455 void NetInternalsMessageHandler::OnCertificatesImported( 1456 const std::string& previous_error, 1457 bool success, 1458 const net::CertificateList& /* unused onc_trusted_certificates */) { 1459 std::string error = previous_error; 1460 if (!success) 1461 error += "Some certificates couldn't be imported. "; 1462 1463 SendJavascriptCommand("receivedONCFileParse", new base::StringValue(error)); 1464 } 1465 1466 void NetInternalsMessageHandler::OnImportONCFile( 1467 const base::ListValue* list) { 1468 std::string onc_blob; 1469 std::string passcode; 1470 if (list->GetSize() != 2 || 1471 !list->GetString(0, &onc_blob) || 1472 !list->GetString(1, &passcode)) { 1473 NOTREACHED(); 1474 } 1475 1476 GetNSSCertDatabaseForProfile( 1477 Profile::FromWebUI(web_ui()), 1478 base::Bind(&NetInternalsMessageHandler::ImportONCFileToNSSDB, AsWeakPtr(), 1479 onc_blob, passcode)); 1480 } 1481 1482 void NetInternalsMessageHandler::OnStoreDebugLogs(const base::ListValue* list) { 1483 DCHECK(list); 1484 1485 SendJavascriptCommand("receivedStoreDebugLogs", 1486 new base::StringValue("Creating log file...")); 1487 Profile* profile = Profile::FromWebUI(web_ui()); 1488 const DownloadPrefs* const prefs = DownloadPrefs::FromBrowserContext(profile); 1489 base::FilePath path = prefs->DownloadPath(); 1490 if (file_manager::util::IsUnderNonNativeLocalPath(profile, path)) 1491 path = prefs->GetDefaultDownloadDirectoryForProfile(); 1492 chromeos::DebugLogWriter::StoreLogs( 1493 path, 1494 true, // should_compress 1495 base::Bind(&NetInternalsMessageHandler::OnStoreDebugLogsCompleted, 1496 AsWeakPtr())); 1497 } 1498 1499 void NetInternalsMessageHandler::OnStoreDebugLogsCompleted( 1500 const base::FilePath& log_path, bool succeeded) { 1501 std::string status; 1502 if (succeeded) 1503 status = "Created log file: " + log_path.BaseName().AsUTF8Unsafe(); 1504 else 1505 status = "Failed to create log file"; 1506 SendJavascriptCommand("receivedStoreDebugLogs", 1507 new base::StringValue(status)); 1508 } 1509 1510 void NetInternalsMessageHandler::OnSetNetworkDebugMode( 1511 const base::ListValue* list) { 1512 std::string subsystem; 1513 if (list->GetSize() != 1 || !list->GetString(0, &subsystem)) 1514 NOTREACHED(); 1515 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()-> 1516 SetDebugMode( 1517 subsystem, 1518 base::Bind( 1519 &NetInternalsMessageHandler::OnSetNetworkDebugModeCompleted, 1520 AsWeakPtr(), 1521 subsystem)); 1522 } 1523 1524 void NetInternalsMessageHandler::OnSetNetworkDebugModeCompleted( 1525 const std::string& subsystem, 1526 bool succeeded) { 1527 std::string status; 1528 if (succeeded) 1529 status = "Debug mode is changed to " + subsystem; 1530 else 1531 status = "Failed to change debug mode to " + subsystem; 1532 SendJavascriptCommand("receivedSetNetworkDebugMode", 1533 new base::StringValue(status)); 1534 } 1535 #endif // defined(OS_CHROMEOS) 1536 1537 void NetInternalsMessageHandler::IOThreadImpl::OnSetLogLevel( 1538 const base::ListValue* list) { 1539 int log_level; 1540 std::string log_level_string; 1541 if (!list->GetString(0, &log_level_string) || 1542 !base::StringToInt(log_level_string, &log_level)) { 1543 NOTREACHED(); 1544 return; 1545 } 1546 1547 DCHECK_GE(log_level, net::NetLog::LOG_ALL); 1548 DCHECK_LT(log_level, net::NetLog::LOG_NONE); 1549 net_log()->SetObserverLogLevel( 1550 this, static_cast<net::NetLog::LogLevel>(log_level)); 1551 } 1552 1553 // Note that unlike other methods of IOThreadImpl, this function 1554 // can be called from ANY THREAD. 1555 void NetInternalsMessageHandler::IOThreadImpl::OnAddEntry( 1556 const net::NetLog::Entry& entry) { 1557 BrowserThread::PostTask( 1558 BrowserThread::IO, FROM_HERE, 1559 base::Bind(&IOThreadImpl::AddEntryToQueue, this, entry.ToValue())); 1560 } 1561 1562 void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTestSuite() { 1563 SendJavascriptCommand("receivedStartConnectionTestSuite", NULL); 1564 } 1565 1566 void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTestExperiment( 1567 const ConnectionTester::Experiment& experiment) { 1568 SendJavascriptCommand( 1569 "receivedStartConnectionTestExperiment", 1570 ExperimentToValue(experiment)); 1571 } 1572 1573 void 1574 NetInternalsMessageHandler::IOThreadImpl::OnCompletedConnectionTestExperiment( 1575 const ConnectionTester::Experiment& experiment, 1576 int result) { 1577 base::DictionaryValue* dict = new base::DictionaryValue(); 1578 1579 dict->Set("experiment", ExperimentToValue(experiment)); 1580 dict->SetInteger("result", result); 1581 1582 SendJavascriptCommand( 1583 "receivedCompletedConnectionTestExperiment", 1584 dict); 1585 } 1586 1587 void 1588 NetInternalsMessageHandler::IOThreadImpl::OnCompletedConnectionTestSuite() { 1589 SendJavascriptCommand( 1590 "receivedCompletedConnectionTestSuite", 1591 NULL); 1592 } 1593 1594 // Note that this can be called from ANY THREAD. 1595 void NetInternalsMessageHandler::IOThreadImpl::SendJavascriptCommand( 1596 const std::string& command, 1597 base::Value* arg) { 1598 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { 1599 if (handler_.get() && !was_webui_deleted_) { 1600 // We check |handler_| in case it was deleted on the UI thread earlier 1601 // while we were running on the IO thread. 1602 handler_->SendJavascriptCommand(command, arg); 1603 } else { 1604 delete arg; 1605 } 1606 return; 1607 } 1608 1609 if (!BrowserThread::PostTask( 1610 BrowserThread::UI, FROM_HERE, 1611 base::Bind(&IOThreadImpl::SendJavascriptCommand, this, command, arg))) { 1612 // Failed posting the task, avoid leaking. 1613 delete arg; 1614 } 1615 } 1616 1617 void NetInternalsMessageHandler::IOThreadImpl::AddEntryToQueue( 1618 base::Value* entry) { 1619 DCHECK_CURRENTLY_ON(BrowserThread::IO); 1620 if (!pending_entries_.get()) { 1621 pending_entries_.reset(new base::ListValue()); 1622 BrowserThread::PostDelayedTask( 1623 BrowserThread::IO, FROM_HERE, 1624 base::Bind(&IOThreadImpl::PostPendingEntries, this), 1625 base::TimeDelta::FromMilliseconds(kNetLogEventDelayMilliseconds)); 1626 } 1627 pending_entries_->Append(entry); 1628 } 1629 1630 void NetInternalsMessageHandler::IOThreadImpl::PostPendingEntries() { 1631 DCHECK_CURRENTLY_ON(BrowserThread::IO); 1632 if (pending_entries_.get()) 1633 SendJavascriptCommand("receivedLogEntries", pending_entries_.release()); 1634 } 1635 1636 void NetInternalsMessageHandler::IOThreadImpl::PrePopulateEventList() { 1637 // Use a set to prevent duplicates. 1638 std::set<net::URLRequestContext*> contexts; 1639 for (ContextGetterList::const_iterator getter = context_getters_.begin(); 1640 getter != context_getters_.end(); ++getter) { 1641 contexts.insert((*getter)->GetURLRequestContext()); 1642 } 1643 contexts.insert(io_thread_->globals()->proxy_script_fetcher_context.get()); 1644 contexts.insert(io_thread_->globals()->system_request_context.get()); 1645 1646 // Put together the list of all requests. 1647 std::vector<const net::URLRequest*> requests; 1648 for (std::set<net::URLRequestContext*>::const_iterator context = 1649 contexts.begin(); 1650 context != contexts.end(); ++context) { 1651 std::set<const net::URLRequest*>* context_requests = 1652 (*context)->url_requests(); 1653 for (std::set<const net::URLRequest*>::const_iterator request_it = 1654 context_requests->begin(); 1655 request_it != context_requests->end(); ++request_it) { 1656 DCHECK_EQ(io_thread_->net_log(), (*request_it)->net_log().net_log()); 1657 requests.push_back(*request_it); 1658 } 1659 } 1660 1661 // Sort by creation time. 1662 std::sort(requests.begin(), requests.end(), RequestCreatedBefore); 1663 1664 // Create fake events. 1665 for (std::vector<const net::URLRequest*>::const_iterator request_it = 1666 requests.begin(); 1667 request_it != requests.end(); ++request_it) { 1668 const net::URLRequest* request = *request_it; 1669 net::NetLog::ParametersCallback callback = 1670 base::Bind(&GetRequestStateAsValue, base::Unretained(request)); 1671 1672 // Create and add the entry directly, to avoid sending it to any other 1673 // NetLog observers. 1674 net::NetLog::EntryData entry_data(net::NetLog::TYPE_REQUEST_ALIVE, 1675 request->net_log().source(), 1676 net::NetLog::PHASE_BEGIN, 1677 request->creation_time(), 1678 &callback); 1679 net::NetLog::Entry entry(&entry_data, request->net_log().GetLogLevel()); 1680 1681 // Have to add |entry| to the queue synchronously, as there may already 1682 // be posted tasks queued up to add other events for |request|, which we 1683 // want |entry| to precede. 1684 AddEntryToQueue(entry.ToValue()); 1685 } 1686 } 1687 1688 } // namespace 1689 1690 1691 //////////////////////////////////////////////////////////////////////////////// 1692 // 1693 // NetInternalsUI 1694 // 1695 //////////////////////////////////////////////////////////////////////////////// 1696 1697 // static 1698 base::Value* NetInternalsUI::GetConstants() { 1699 base::DictionaryValue* constants_dict = net::NetLogLogger::GetConstants(); 1700 DCHECK(constants_dict); 1701 1702 // Add a dictionary with the version of the client and its command line 1703 // arguments. 1704 { 1705 base::DictionaryValue* dict = new base::DictionaryValue(); 1706 1707 chrome::VersionInfo version_info; 1708 1709 if (!version_info.is_valid()) { 1710 DLOG(ERROR) << "Unable to create chrome::VersionInfo"; 1711 } else { 1712 // We have everything we need to send the right values. 1713 dict->SetString("name", version_info.Name()); 1714 dict->SetString("version", version_info.Version()); 1715 dict->SetString("cl", version_info.LastChange()); 1716 dict->SetString("version_mod", 1717 chrome::VersionInfo::GetVersionStringModifier()); 1718 dict->SetString("official", 1719 version_info.IsOfficialBuild() ? "official" : 1720 "unofficial"); 1721 dict->SetString("os_type", version_info.OSType()); 1722 dict->SetString("command_line", 1723 CommandLine::ForCurrentProcess()->GetCommandLineString()); 1724 } 1725 1726 constants_dict->Set("clientInfo", dict); 1727 } 1728 1729 return constants_dict; 1730 } 1731 1732 NetInternalsUI::NetInternalsUI(content::WebUI* web_ui) 1733 : WebUIController(web_ui) { 1734 web_ui->AddMessageHandler(new NetInternalsMessageHandler()); 1735 1736 // Set up the chrome://net-internals/ source. 1737 Profile* profile = Profile::FromWebUI(web_ui); 1738 content::WebUIDataSource::Add(profile, CreateNetInternalsHTMLSource()); 1739 } 1740