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