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