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