1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/ui/webui/net_internals_ui.h" 6 7 #include <algorithm> 8 #include <string> 9 #include <utility> 10 #include <vector> 11 12 #include "base/base64.h" 13 #include "base/command_line.h" 14 #include "base/file_util.h" 15 #include "base/memory/singleton.h" 16 #include "base/message_loop.h" 17 #include "base/path_service.h" 18 #include "base/string_number_conversions.h" 19 #include "base/string_piece.h" 20 #include "base/string_split.h" 21 #include "base/string_util.h" 22 #include "base/utf_string_conversions.h" 23 #include "base/values.h" 24 #include "chrome/browser/browser_process.h" 25 #include "chrome/browser/io_thread.h" 26 #include "chrome/browser/net/chrome_net_log.h" 27 #include "chrome/browser/net/connection_tester.h" 28 #include "chrome/browser/net/passive_log_collector.h" 29 #include "chrome/browser/net/url_fixer_upper.h" 30 #include "chrome/browser/platform_util.h" 31 #include "chrome/browser/prefs/pref_member.h" 32 #include "chrome/browser/profiles/profile.h" 33 #include "chrome/browser/ui/shell_dialogs.h" 34 #include "chrome/browser/ui/webui/chrome_url_data_manager.h" 35 #include "chrome/common/chrome_paths.h" 36 #include "chrome/common/chrome_version_info.h" 37 #include "chrome/common/jstemplate_builder.h" 38 #include "chrome/common/pref_names.h" 39 #include "chrome/common/url_constants.h" 40 #include "content/browser/browser_thread.h" 41 #include "content/browser/tab_contents/tab_contents.h" 42 #include "content/browser/tab_contents/tab_contents_view.h" 43 #include "content/common/notification_details.h" 44 #include "grit/generated_resources.h" 45 #include "grit/net_internals_resources.h" 46 #include "net/base/escape.h" 47 #include "net/base/host_resolver_impl.h" 48 #include "net/base/net_errors.h" 49 #include "net/base/net_util.h" 50 #include "net/base/sys_addrinfo.h" 51 #include "net/base/x509_cert_types.h" 52 #include "net/disk_cache/disk_cache.h" 53 #include "net/http/http_alternate_protocols.h" 54 #include "net/http/http_cache.h" 55 #include "net/http/http_network_layer.h" 56 #include "net/http/http_network_session.h" 57 #include "net/http/http_stream_factory.h" 58 #include "net/proxy/proxy_service.h" 59 #include "net/url_request/url_request_context.h" 60 #include "net/url_request/url_request_context_getter.h" 61 #include "ui/base/l10n/l10n_util.h" 62 #include "ui/base/resource/resource_bundle.h" 63 64 #ifdef OS_WIN 65 #include "chrome/browser/net/service_providers_win.h" 66 #endif 67 68 namespace { 69 70 // Delay between when an event occurs and when it is passed to the Javascript 71 // page. All events that occur during this period are grouped together and 72 // sent to the page at once, which reduces context switching and CPU usage. 73 const int kNetLogEventDelayMilliseconds = 100; 74 75 // Returns the HostCache for |context|'s primary HostResolver, or NULL if 76 // there is none. 77 net::HostCache* GetHostResolverCache(net::URLRequestContext* context) { 78 net::HostResolverImpl* host_resolver_impl = 79 context->host_resolver()->GetAsHostResolverImpl(); 80 81 if (!host_resolver_impl) 82 return NULL; 83 84 return host_resolver_impl->cache(); 85 } 86 87 // Returns the disk cache backend for |context| if there is one, or NULL. 88 disk_cache::Backend* GetDiskCacheBackend(net::URLRequestContext* context) { 89 if (!context->http_transaction_factory()) 90 return NULL; 91 92 net::HttpCache* http_cache = context->http_transaction_factory()->GetCache(); 93 if (!http_cache) 94 return NULL; 95 96 return http_cache->GetCurrentBackend(); 97 } 98 99 // Returns the http network session for |context| if there is one. 100 // Otherwise, returns NULL. 101 net::HttpNetworkSession* GetHttpNetworkSession( 102 net::URLRequestContext* context) { 103 if (!context->http_transaction_factory()) 104 return NULL; 105 106 return context->http_transaction_factory()->GetSession(); 107 } 108 109 Value* ExperimentToValue(const ConnectionTester::Experiment& experiment) { 110 DictionaryValue* dict = new DictionaryValue(); 111 112 if (experiment.url.is_valid()) 113 dict->SetString("url", experiment.url.spec()); 114 115 dict->SetString("proxy_settings_experiment", 116 ConnectionTester::ProxySettingsExperimentDescription( 117 experiment.proxy_settings_experiment)); 118 dict->SetString("host_resolver_experiment", 119 ConnectionTester::HostResolverExperimentDescription( 120 experiment.host_resolver_experiment)); 121 return dict; 122 } 123 124 class NetInternalsHTMLSource : public ChromeURLDataManager::DataSource { 125 public: 126 NetInternalsHTMLSource(); 127 128 // Called when the network layer has requested a resource underneath 129 // the path we registered. 130 virtual void StartDataRequest(const std::string& path, 131 bool is_incognito, 132 int request_id); 133 virtual std::string GetMimeType(const std::string&) const; 134 135 private: 136 ~NetInternalsHTMLSource() {} 137 DISALLOW_COPY_AND_ASSIGN(NetInternalsHTMLSource); 138 }; 139 140 // This class receives javascript messages from the renderer. 141 // Note that the WebUI infrastructure runs on the UI thread, therefore all of 142 // this class's methods are expected to run on the UI thread. 143 // 144 // Since the network code we want to run lives on the IO thread, we proxy 145 // almost everything over to NetInternalsMessageHandler::IOThreadImpl, which 146 // runs on the IO thread. 147 // 148 // TODO(eroman): Can we start on the IO thread to begin with? 149 class NetInternalsMessageHandler 150 : public WebUIMessageHandler, 151 public SelectFileDialog::Listener, 152 public base::SupportsWeakPtr<NetInternalsMessageHandler>, 153 public NotificationObserver { 154 public: 155 NetInternalsMessageHandler(); 156 virtual ~NetInternalsMessageHandler(); 157 158 // WebUIMessageHandler implementation. 159 virtual WebUIMessageHandler* Attach(WebUI* web_ui); 160 virtual void RegisterMessages(); 161 162 // Executes the javascript function |function_name| in the renderer, passing 163 // it the argument |value|. 164 void CallJavascriptFunction(const std::wstring& function_name, 165 const Value* value); 166 167 // NotificationObserver implementation. 168 virtual void Observe(NotificationType type, 169 const NotificationSource& source, 170 const NotificationDetails& details); 171 172 // Javascript message handlers. 173 void OnRendererReady(const ListValue* list); 174 void OnEnableHttpThrottling(const ListValue* list); 175 176 // SelectFileDialog::Listener implementation 177 virtual void FileSelected(const FilePath& path, int index, void* params); 178 virtual void FileSelectionCanceled(void* params); 179 180 // The only callback handled on the UI thread. As it needs to access fields 181 // from |web_ui_|, it can't be called on the IO thread. 182 void OnLoadLogFile(const ListValue* list); 183 184 private: 185 class IOThreadImpl; 186 187 // Task run on the FILE thread to read the contents of a log file. The result 188 // is then passed to IOThreadImpl's CallJavascriptFunction, which sends it 189 // back to the web page. IOThreadImpl is used instead of the 190 // NetInternalsMessageHandler directly because it checks if the message 191 // handler has been destroyed in the meantime. 192 class ReadLogFileTask : public Task { 193 public: 194 ReadLogFileTask(IOThreadImpl* proxy, const FilePath& path); 195 196 virtual void Run(); 197 198 private: 199 // IOThreadImpl implements existence checks already. Simpler to reused them 200 // then to reimplement them. 201 scoped_refptr<IOThreadImpl> proxy_; 202 203 // Path of the file to open. 204 const FilePath path_; 205 }; 206 207 // The pref member about whether HTTP throttling is enabled, which needs to 208 // be accessed on the UI thread. 209 BooleanPrefMember http_throttling_enabled_; 210 211 // OnRendererReady invokes this callback to do the part of message handling 212 // that needs to happen on the IO thread. 213 scoped_ptr<WebUI::MessageCallback> renderer_ready_io_callback_; 214 215 // This is the "real" message handler, which lives on the IO thread. 216 scoped_refptr<IOThreadImpl> proxy_; 217 218 // Used for loading log files. 219 scoped_refptr<SelectFileDialog> select_log_file_dialog_; 220 221 DISALLOW_COPY_AND_ASSIGN(NetInternalsMessageHandler); 222 }; 223 224 // This class is the "real" message handler. It is allocated and destroyed on 225 // the UI thread. With the exception of OnAddEntry, OnWebUIDeleted, and 226 // CallJavascriptFunction, its methods are all expected to be called from the IO 227 // thread. OnAddEntry and CallJavascriptFunction can be called from any thread, 228 // and OnWebUIDeleted can only be called from the UI thread. 229 class NetInternalsMessageHandler::IOThreadImpl 230 : public base::RefCountedThreadSafe< 231 NetInternalsMessageHandler::IOThreadImpl, 232 BrowserThread::DeleteOnUIThread>, 233 public ChromeNetLog::ThreadSafeObserver, 234 public ConnectionTester::Delegate { 235 public: 236 // Type for methods that can be used as MessageHandler callbacks. 237 typedef void (IOThreadImpl::*MessageHandler)(const ListValue*); 238 239 // Creates a proxy for |handler| that will live on the IO thread. 240 // |handler| is a weak pointer, since it is possible for the 241 // WebUIMessageHandler to be deleted on the UI thread while we were executing 242 // on the IO thread. |io_thread| is the global IOThread (it is passed in as 243 // an argument since we need to grab it from the UI thread). 244 IOThreadImpl( 245 const base::WeakPtr<NetInternalsMessageHandler>& handler, 246 IOThread* io_thread, 247 net::URLRequestContextGetter* context_getter); 248 249 // Creates a callback that will run |method| on the IO thread. 250 // 251 // This can be used with WebUI::RegisterMessageCallback() to bind to a method 252 // on the IO thread. 253 WebUI::MessageCallback* CreateCallback(MessageHandler method); 254 255 // Called once the WebUI has been deleted (i.e. renderer went away), on the 256 // IO thread. 257 void Detach(); 258 259 // Sends all passive log entries in |passive_entries| to the Javascript 260 // handler, called on the IO thread. 261 void SendPassiveLogEntries(const ChromeNetLog::EntryList& passive_entries); 262 263 // Called when the WebUI is deleted. Prevents calling Javascript functions 264 // afterwards. Called on UI thread. 265 void OnWebUIDeleted(); 266 267 //-------------------------------- 268 // Javascript message handlers: 269 //-------------------------------- 270 271 void OnRendererReady(const ListValue* list); 272 273 void OnGetProxySettings(const ListValue* list); 274 void OnReloadProxySettings(const ListValue* list); 275 void OnGetBadProxies(const ListValue* list); 276 void OnClearBadProxies(const ListValue* list); 277 void OnGetHostResolverInfo(const ListValue* list); 278 void OnClearHostResolverCache(const ListValue* list); 279 void OnEnableIPv6(const ListValue* list); 280 void OnStartConnectionTests(const ListValue* list); 281 void OnHSTSQuery(const ListValue* list); 282 void OnHSTSAdd(const ListValue* list); 283 void OnHSTSDelete(const ListValue* list); 284 void OnGetHttpCacheInfo(const ListValue* list); 285 void OnGetSocketPoolInfo(const ListValue* list); 286 void OnCloseIdleSockets(const ListValue* list); 287 void OnFlushSocketPools(const ListValue* list); 288 void OnGetSpdySessionInfo(const ListValue* list); 289 void OnGetSpdyStatus(const ListValue* list); 290 void OnGetSpdyAlternateProtocolMappings(const ListValue* list); 291 #ifdef OS_WIN 292 void OnGetServiceProviders(const ListValue* list); 293 #endif 294 295 void OnSetLogLevel(const ListValue* list); 296 297 // ChromeNetLog::ThreadSafeObserver implementation: 298 virtual void OnAddEntry(net::NetLog::EventType type, 299 const base::TimeTicks& time, 300 const net::NetLog::Source& source, 301 net::NetLog::EventPhase phase, 302 net::NetLog::EventParameters* params); 303 304 // ConnectionTester::Delegate implementation: 305 virtual void OnStartConnectionTestSuite(); 306 virtual void OnStartConnectionTestExperiment( 307 const ConnectionTester::Experiment& experiment); 308 virtual void OnCompletedConnectionTestExperiment( 309 const ConnectionTester::Experiment& experiment, 310 int result); 311 virtual void OnCompletedConnectionTestSuite(); 312 313 // Helper that executes |function_name| in the attached renderer. 314 // The function takes ownership of |arg|. Note that this can be called from 315 // any thread. 316 void CallJavascriptFunction(const std::wstring& function_name, Value* arg); 317 318 private: 319 friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>; 320 friend class DeleteTask<IOThreadImpl>; 321 322 ~IOThreadImpl(); 323 324 class CallbackHelper; 325 326 // Helper that runs |method| with |arg|, and deletes |arg| on completion. 327 void DispatchToMessageHandler(ListValue* arg, MessageHandler method); 328 329 // Adds |entry| to the queue of pending log entries to be sent to the page via 330 // Javascript. Must be called on the IO Thread. Also creates a delayed task 331 // that will call PostPendingEntries, if there isn't one already. 332 void AddEntryToQueue(Value* entry); 333 334 // Sends all pending entries to the page via Javascript, and clears the list 335 // of pending entries. Sending multiple entries at once results in a 336 // significant reduction of CPU usage when a lot of events are happening. 337 // Must be called on the IO Thread. 338 void PostPendingEntries(); 339 340 // Pointer to the UI-thread message handler. Only access this from 341 // the UI thread. 342 base::WeakPtr<NetInternalsMessageHandler> handler_; 343 344 // The global IOThread, which contains the global NetLog to observer. 345 IOThread* io_thread_; 346 347 scoped_refptr<net::URLRequestContextGetter> context_getter_; 348 349 // Helper that runs the suite of connection tests. 350 scoped_ptr<ConnectionTester> connection_tester_; 351 352 // True if the Web UI has been deleted. This is used to prevent calling 353 // Javascript functions after the Web UI is destroyed. On refresh, the 354 // messages can end up being sent to the refreshed page, causing duplicate 355 // or partial entries. 356 // 357 // This is only read and written to on the UI thread. 358 bool was_webui_deleted_; 359 360 // True if we have attached an observer to the NetLog already. 361 bool is_observing_log_; 362 363 // Log entries that have yet to be passed along to Javascript page. Non-NULL 364 // when and only when there is a pending delayed task to call 365 // PostPendingEntries. Read and written to exclusively on the IO Thread. 366 scoped_ptr<ListValue> pending_entries_; 367 }; 368 369 // Helper class for a WebUI::MessageCallback which when executed calls 370 // instance->*method(value) on the IO thread. 371 class NetInternalsMessageHandler::IOThreadImpl::CallbackHelper 372 : public WebUI::MessageCallback { 373 public: 374 CallbackHelper(IOThreadImpl* instance, IOThreadImpl::MessageHandler method) 375 : instance_(instance), 376 method_(method) { 377 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 378 } 379 380 virtual void RunWithParams(const Tuple1<const ListValue*>& params) { 381 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 382 383 // We need to make a copy of the value in order to pass it over to the IO 384 // thread. We will delete this in IOThreadImpl::DispatchMessageHandler(). 385 ListValue* list_copy = static_cast<ListValue*>( 386 params.a ? params.a->DeepCopy() : NULL); 387 388 if (!BrowserThread::PostTask( 389 BrowserThread::IO, FROM_HERE, 390 NewRunnableMethod(instance_.get(), 391 &IOThreadImpl::DispatchToMessageHandler, 392 list_copy, method_))) { 393 // Failed posting the task, avoid leaking |list_copy|. 394 delete list_copy; 395 } 396 } 397 398 private: 399 scoped_refptr<IOThreadImpl> instance_; 400 IOThreadImpl::MessageHandler method_; 401 }; 402 403 //////////////////////////////////////////////////////////////////////////////// 404 // 405 // NetInternalsHTMLSource 406 // 407 //////////////////////////////////////////////////////////////////////////////// 408 409 NetInternalsHTMLSource::NetInternalsHTMLSource() 410 : DataSource(chrome::kChromeUINetInternalsHost, MessageLoop::current()) { 411 } 412 413 void NetInternalsHTMLSource::StartDataRequest(const std::string& path, 414 bool is_incognito, 415 int request_id) { 416 DictionaryValue localized_strings; 417 SetFontAndTextDirection(&localized_strings); 418 419 // The provided "path" may contain a fragment, or query section. We only 420 // care about the path itself, and will disregard anything else. 421 std::string filename = 422 GURL(std::string("chrome://net/") + path).path().substr(1); 423 424 // The source for the net internals page is flattened during compilation, so 425 // the only resource that should legitimately be requested is the main file. 426 // Note that users can type anything into the address bar, though, so we must 427 // handle arbitrary input. 428 if (filename.empty() || filename == "index.html") { 429 base::StringPiece html( 430 ResourceBundle::GetSharedInstance().GetRawDataResource( 431 IDR_NET_INTERNALS_INDEX_HTML)); 432 std::string full_html(html.data(), html.size()); 433 jstemplate_builder::AppendJsonHtml(&localized_strings, &full_html); 434 jstemplate_builder::AppendI18nTemplateSourceHtml(&full_html); 435 jstemplate_builder::AppendI18nTemplateProcessHtml(&full_html); 436 jstemplate_builder::AppendJsTemplateSourceHtml(&full_html); 437 438 scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes); 439 html_bytes->data.resize(full_html.size()); 440 std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin()); 441 SendResponse(request_id, html_bytes); 442 return; 443 } 444 445 const std::string data_string("<p style='color:red'>Failed to read resource" + 446 EscapeForHTML(filename) + "</p>"); 447 scoped_refptr<RefCountedBytes> bytes(new RefCountedBytes); 448 bytes->data.resize(data_string.size()); 449 std::copy(data_string.begin(), data_string.end(), bytes->data.begin()); 450 SendResponse(request_id, bytes); 451 } 452 453 std::string NetInternalsHTMLSource::GetMimeType(const std::string&) const { 454 return "text/html"; 455 } 456 457 //////////////////////////////////////////////////////////////////////////////// 458 // 459 // NetInternalsMessageHandler 460 // 461 //////////////////////////////////////////////////////////////////////////////// 462 463 NetInternalsMessageHandler::NetInternalsMessageHandler() {} 464 465 NetInternalsMessageHandler::~NetInternalsMessageHandler() { 466 if (proxy_) { 467 proxy_.get()->OnWebUIDeleted(); 468 // Notify the handler on the IO thread that the renderer is gone. 469 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 470 NewRunnableMethod(proxy_.get(), &IOThreadImpl::Detach)); 471 } 472 if (select_log_file_dialog_) 473 select_log_file_dialog_->ListenerDestroyed(); 474 } 475 476 WebUIMessageHandler* NetInternalsMessageHandler::Attach(WebUI* web_ui) { 477 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 478 479 PrefService* pref_service = web_ui->GetProfile()->GetPrefs(); 480 http_throttling_enabled_.Init(prefs::kHttpThrottlingEnabled, pref_service, 481 this); 482 483 proxy_ = new IOThreadImpl(this->AsWeakPtr(), g_browser_process->io_thread(), 484 web_ui->GetProfile()->GetRequestContext()); 485 renderer_ready_io_callback_.reset( 486 proxy_->CreateCallback(&IOThreadImpl::OnRendererReady)); 487 488 WebUIMessageHandler* result = WebUIMessageHandler::Attach(web_ui); 489 return result; 490 } 491 492 void NetInternalsMessageHandler::FileSelected( 493 const FilePath& path, int index, void* params) { 494 select_log_file_dialog_.release(); 495 BrowserThread::PostTask( 496 BrowserThread::FILE, FROM_HERE, 497 new ReadLogFileTask(proxy_.get(), path)); 498 } 499 500 void NetInternalsMessageHandler::FileSelectionCanceled(void* params) { 501 select_log_file_dialog_.release(); 502 } 503 504 void NetInternalsMessageHandler::OnLoadLogFile(const ListValue* list) { 505 // Only allow a single dialog at a time. 506 if (select_log_file_dialog_.get()) 507 return; 508 select_log_file_dialog_ = SelectFileDialog::Create(this); 509 select_log_file_dialog_->SelectFile( 510 SelectFileDialog::SELECT_OPEN_FILE, string16(), FilePath(), NULL, 0, 511 FILE_PATH_LITERAL(""), web_ui_->tab_contents(), 512 web_ui_->tab_contents()->view()->GetTopLevelNativeWindow(), NULL); 513 } 514 515 void NetInternalsMessageHandler::RegisterMessages() { 516 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 517 // Only callback handled on UI thread. 518 web_ui_->RegisterMessageCallback( 519 "loadLogFile", 520 NewCallback(this, &NetInternalsMessageHandler::OnLoadLogFile)); 521 522 web_ui_->RegisterMessageCallback( 523 "notifyReady", 524 NewCallback(this, &NetInternalsMessageHandler::OnRendererReady)); 525 web_ui_->RegisterMessageCallback( 526 "getProxySettings", 527 proxy_->CreateCallback(&IOThreadImpl::OnGetProxySettings)); 528 web_ui_->RegisterMessageCallback( 529 "reloadProxySettings", 530 proxy_->CreateCallback(&IOThreadImpl::OnReloadProxySettings)); 531 web_ui_->RegisterMessageCallback( 532 "getBadProxies", 533 proxy_->CreateCallback(&IOThreadImpl::OnGetBadProxies)); 534 web_ui_->RegisterMessageCallback( 535 "clearBadProxies", 536 proxy_->CreateCallback(&IOThreadImpl::OnClearBadProxies)); 537 web_ui_->RegisterMessageCallback( 538 "getHostResolverInfo", 539 proxy_->CreateCallback(&IOThreadImpl::OnGetHostResolverInfo)); 540 web_ui_->RegisterMessageCallback( 541 "clearHostResolverCache", 542 proxy_->CreateCallback(&IOThreadImpl::OnClearHostResolverCache)); 543 web_ui_->RegisterMessageCallback( 544 "enableIPv6", 545 proxy_->CreateCallback(&IOThreadImpl::OnEnableIPv6)); 546 web_ui_->RegisterMessageCallback( 547 "startConnectionTests", 548 proxy_->CreateCallback(&IOThreadImpl::OnStartConnectionTests)); 549 web_ui_->RegisterMessageCallback( 550 "hstsQuery", 551 proxy_->CreateCallback(&IOThreadImpl::OnHSTSQuery)); 552 web_ui_->RegisterMessageCallback( 553 "hstsAdd", 554 proxy_->CreateCallback(&IOThreadImpl::OnHSTSAdd)); 555 web_ui_->RegisterMessageCallback( 556 "hstsDelete", 557 proxy_->CreateCallback(&IOThreadImpl::OnHSTSDelete)); 558 web_ui_->RegisterMessageCallback( 559 "getHttpCacheInfo", 560 proxy_->CreateCallback(&IOThreadImpl::OnGetHttpCacheInfo)); 561 web_ui_->RegisterMessageCallback( 562 "getSocketPoolInfo", 563 proxy_->CreateCallback(&IOThreadImpl::OnGetSocketPoolInfo)); 564 web_ui_->RegisterMessageCallback( 565 "closeIdleSockets", 566 proxy_->CreateCallback(&IOThreadImpl::OnCloseIdleSockets)); 567 web_ui_->RegisterMessageCallback( 568 "flushSocketPools", 569 proxy_->CreateCallback(&IOThreadImpl::OnFlushSocketPools)); 570 web_ui_->RegisterMessageCallback( 571 "getSpdySessionInfo", 572 proxy_->CreateCallback(&IOThreadImpl::OnGetSpdySessionInfo)); 573 web_ui_->RegisterMessageCallback( 574 "getSpdyStatus", 575 proxy_->CreateCallback(&IOThreadImpl::OnGetSpdyStatus)); 576 web_ui_->RegisterMessageCallback( 577 "getSpdyAlternateProtocolMappings", 578 proxy_->CreateCallback( 579 &IOThreadImpl::OnGetSpdyAlternateProtocolMappings)); 580 #ifdef OS_WIN 581 web_ui_->RegisterMessageCallback( 582 "getServiceProviders", 583 proxy_->CreateCallback(&IOThreadImpl::OnGetServiceProviders)); 584 #endif 585 586 web_ui_->RegisterMessageCallback( 587 "setLogLevel", 588 proxy_->CreateCallback(&IOThreadImpl::OnSetLogLevel)); 589 590 web_ui_->RegisterMessageCallback( 591 "enableHttpThrottling", 592 NewCallback(this, &NetInternalsMessageHandler::OnEnableHttpThrottling)); 593 } 594 595 void NetInternalsMessageHandler::CallJavascriptFunction( 596 const std::wstring& function_name, 597 const Value* value) { 598 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 599 if (value) { 600 web_ui_->CallJavascriptFunction(WideToASCII(function_name), *value); 601 } else { 602 web_ui_->CallJavascriptFunction(WideToASCII(function_name)); 603 } 604 } 605 606 void NetInternalsMessageHandler::Observe(NotificationType type, 607 const NotificationSource& source, 608 const NotificationDetails& details) { 609 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 610 DCHECK_EQ(type.value, NotificationType::PREF_CHANGED); 611 612 std::string* pref_name = Details<std::string>(details).ptr(); 613 if (*pref_name == prefs::kHttpThrottlingEnabled) { 614 scoped_ptr<Value> enabled( 615 Value::CreateBooleanValue(*http_throttling_enabled_)); 616 617 CallJavascriptFunction( 618 L"g_browser.receivedHttpThrottlingEnabledPrefChanged", enabled.get()); 619 } 620 } 621 622 void NetInternalsMessageHandler::OnRendererReady(const ListValue* list) { 623 CHECK(renderer_ready_io_callback_.get()); 624 renderer_ready_io_callback_->Run(list); 625 626 scoped_ptr<Value> enabled( 627 Value::CreateBooleanValue(*http_throttling_enabled_)); 628 CallJavascriptFunction( 629 L"g_browser.receivedHttpThrottlingEnabledPrefChanged", enabled.get()); 630 } 631 632 void NetInternalsMessageHandler::OnEnableHttpThrottling(const ListValue* list) { 633 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 634 635 bool enable = false; 636 if (!list->GetBoolean(0, &enable)) { 637 NOTREACHED(); 638 return; 639 } 640 641 http_throttling_enabled_.SetValue(enable); 642 } 643 644 //////////////////////////////////////////////////////////////////////////////// 645 // 646 // NetInternalsMessageHandler::ReadLogFileTask 647 // 648 //////////////////////////////////////////////////////////////////////////////// 649 650 NetInternalsMessageHandler::ReadLogFileTask::ReadLogFileTask( 651 IOThreadImpl* proxy, const FilePath& path) 652 : proxy_(proxy), path_(path) { 653 } 654 655 void NetInternalsMessageHandler::ReadLogFileTask::Run() { 656 std::string file_contents; 657 if (!file_util::ReadFileToString(path_, &file_contents)) 658 return; 659 proxy_->CallJavascriptFunction(L"g_browser.loadedLogFile", 660 new StringValue(file_contents)); 661 } 662 663 //////////////////////////////////////////////////////////////////////////////// 664 // 665 // NetInternalsMessageHandler::IOThreadImpl 666 // 667 //////////////////////////////////////////////////////////////////////////////// 668 669 NetInternalsMessageHandler::IOThreadImpl::IOThreadImpl( 670 const base::WeakPtr<NetInternalsMessageHandler>& handler, 671 IOThread* io_thread, 672 net::URLRequestContextGetter* context_getter) 673 : ThreadSafeObserver(net::NetLog::LOG_ALL_BUT_BYTES), 674 handler_(handler), 675 io_thread_(io_thread), 676 context_getter_(context_getter), 677 was_webui_deleted_(false), 678 is_observing_log_(false) { 679 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 680 } 681 682 NetInternalsMessageHandler::IOThreadImpl::~IOThreadImpl() { 683 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 684 } 685 686 WebUI::MessageCallback* 687 NetInternalsMessageHandler::IOThreadImpl::CreateCallback( 688 MessageHandler method) { 689 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 690 return new CallbackHelper(this, method); 691 } 692 693 void NetInternalsMessageHandler::IOThreadImpl::Detach() { 694 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 695 // Unregister with network stack to observe events. 696 if (is_observing_log_) 697 io_thread_->net_log()->RemoveObserver(this); 698 699 // Cancel any in-progress connection tests. 700 connection_tester_.reset(); 701 } 702 703 void NetInternalsMessageHandler::IOThreadImpl::SendPassiveLogEntries( 704 const ChromeNetLog::EntryList& passive_entries) { 705 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 706 ListValue* dict_list = new ListValue(); 707 for (size_t i = 0; i < passive_entries.size(); ++i) { 708 const ChromeNetLog::Entry& e = passive_entries[i]; 709 dict_list->Append(net::NetLog::EntryToDictionaryValue(e.type, 710 e.time, 711 e.source, 712 e.phase, 713 e.params, 714 false)); 715 } 716 717 CallJavascriptFunction(L"g_browser.receivedPassiveLogEntries", dict_list); 718 } 719 720 void NetInternalsMessageHandler::IOThreadImpl::OnWebUIDeleted() { 721 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 722 was_webui_deleted_ = true; 723 } 724 725 void NetInternalsMessageHandler::IOThreadImpl::OnRendererReady( 726 const ListValue* list) { 727 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 728 DCHECK(!is_observing_log_) << "notifyReady called twice"; 729 730 // Tell the javascript about the relationship between event type enums and 731 // their symbolic name. 732 { 733 std::vector<net::NetLog::EventType> event_types = 734 net::NetLog::GetAllEventTypes(); 735 736 DictionaryValue* dict = new DictionaryValue(); 737 738 for (size_t i = 0; i < event_types.size(); ++i) { 739 const char* name = net::NetLog::EventTypeToString(event_types[i]); 740 dict->SetInteger(name, static_cast<int>(event_types[i])); 741 } 742 743 CallJavascriptFunction(L"g_browser.receivedLogEventTypeConstants", dict); 744 } 745 746 // Tell the javascript about the version of the client and its 747 // command line arguments. 748 { 749 DictionaryValue* dict = new DictionaryValue(); 750 751 chrome::VersionInfo version_info; 752 753 if (!version_info.is_valid()) { 754 DLOG(ERROR) << "Unable to create chrome::VersionInfo"; 755 } else { 756 // We have everything we need to send the right values. 757 dict->SetString("version", version_info.Version()); 758 dict->SetString("cl", version_info.LastChange()); 759 dict->SetString("version_mod", 760 platform_util::GetVersionStringModifier()); 761 dict->SetString("official", 762 l10n_util::GetStringUTF16( 763 version_info.IsOfficialBuild() ? 764 IDS_ABOUT_VERSION_OFFICIAL 765 : IDS_ABOUT_VERSION_UNOFFICIAL)); 766 767 dict->SetString("command_line", 768 CommandLine::ForCurrentProcess()->command_line_string()); 769 } 770 771 CallJavascriptFunction(L"g_browser.receivedClientInfo", 772 dict); 773 } 774 775 // Tell the javascript about the relationship between load flag enums and 776 // their symbolic name. 777 { 778 DictionaryValue* dict = new DictionaryValue(); 779 780 #define LOAD_FLAG(label, value) \ 781 dict->SetInteger(# label, static_cast<int>(value)); 782 #include "net/base/load_flags_list.h" 783 #undef LOAD_FLAG 784 785 CallJavascriptFunction(L"g_browser.receivedLoadFlagConstants", dict); 786 } 787 788 // Tell the javascript about the relationship between net error codes and 789 // their symbolic name. 790 { 791 DictionaryValue* dict = new DictionaryValue(); 792 793 #define NET_ERROR(label, value) \ 794 dict->SetInteger(# label, static_cast<int>(value)); 795 #include "net/base/net_error_list.h" 796 #undef NET_ERROR 797 798 CallJavascriptFunction(L"g_browser.receivedNetErrorConstants", dict); 799 } 800 801 // Tell the javascript about the relationship between event phase enums and 802 // their symbolic name. 803 { 804 DictionaryValue* dict = new DictionaryValue(); 805 806 dict->SetInteger("PHASE_BEGIN", net::NetLog::PHASE_BEGIN); 807 dict->SetInteger("PHASE_END", net::NetLog::PHASE_END); 808 dict->SetInteger("PHASE_NONE", net::NetLog::PHASE_NONE); 809 810 CallJavascriptFunction(L"g_browser.receivedLogEventPhaseConstants", dict); 811 } 812 813 // Tell the javascript about the relationship between source type enums and 814 // their symbolic names. 815 { 816 DictionaryValue* dict = new DictionaryValue(); 817 818 #define SOURCE_TYPE(label, value) dict->SetInteger(# label, value); 819 #include "net/base/net_log_source_type_list.h" 820 #undef SOURCE_TYPE 821 822 CallJavascriptFunction(L"g_browser.receivedLogSourceTypeConstants", dict); 823 } 824 825 // Tell the javascript about the relationship between LogLevel enums and their 826 // symbolic names. 827 { 828 DictionaryValue* dict = new DictionaryValue(); 829 830 dict->SetInteger("LOG_ALL", net::NetLog::LOG_ALL); 831 dict->SetInteger("LOG_ALL_BUT_BYTES", net::NetLog::LOG_ALL_BUT_BYTES); 832 dict->SetInteger("LOG_BASIC", net::NetLog::LOG_BASIC); 833 834 CallJavascriptFunction(L"g_browser.receivedLogLevelConstants", dict); 835 } 836 837 // Tell the javascript about the relationship between address family enums and 838 // their symbolic names. 839 { 840 DictionaryValue* dict = new DictionaryValue(); 841 842 dict->SetInteger("ADDRESS_FAMILY_UNSPECIFIED", 843 net::ADDRESS_FAMILY_UNSPECIFIED); 844 dict->SetInteger("ADDRESS_FAMILY_IPV4", 845 net::ADDRESS_FAMILY_IPV4); 846 dict->SetInteger("ADDRESS_FAMILY_IPV6", 847 net::ADDRESS_FAMILY_IPV6); 848 849 CallJavascriptFunction(L"g_browser.receivedAddressFamilyConstants", dict); 850 } 851 852 // Tell the javascript how the "time ticks" values we have given it relate to 853 // actual system times. (We used time ticks throughout since they are stable 854 // across system clock changes). 855 { 856 int64 cur_time_ms = (base::Time::Now() - base::Time()).InMilliseconds(); 857 858 int64 cur_time_ticks_ms = 859 (base::TimeTicks::Now() - base::TimeTicks()).InMilliseconds(); 860 861 // If we add this number to a time tick value, it gives the timestamp. 862 int64 tick_to_time_ms = cur_time_ms - cur_time_ticks_ms; 863 864 // Chrome on all platforms stores times using the Windows epoch 865 // (Jan 1 1601), but the javascript wants a unix epoch. 866 // TODO(eroman): Getting the timestamp relative the to unix epoch should 867 // be part of the time library. 868 const int64 kUnixEpochMs = 11644473600000LL; 869 int64 tick_to_unix_time_ms = tick_to_time_ms - kUnixEpochMs; 870 871 // Pass it as a string, since it may be too large to fit in an integer. 872 CallJavascriptFunction(L"g_browser.receivedTimeTickOffset", 873 Value::CreateStringValue( 874 base::Int64ToString(tick_to_unix_time_ms))); 875 } 876 877 // Register with network stack to observe events. 878 is_observing_log_ = true; 879 ChromeNetLog::EntryList entries; 880 io_thread_->net_log()->AddObserverAndGetAllPassivelyCapturedEvents(this, 881 &entries); 882 SendPassiveLogEntries(entries); 883 } 884 885 void NetInternalsMessageHandler::IOThreadImpl::OnGetProxySettings( 886 const ListValue* list) { 887 net::URLRequestContext* context = context_getter_->GetURLRequestContext(); 888 net::ProxyService* proxy_service = context->proxy_service(); 889 890 DictionaryValue* dict = new DictionaryValue(); 891 if (proxy_service->fetched_config().is_valid()) 892 dict->Set("original", proxy_service->fetched_config().ToValue()); 893 if (proxy_service->config().is_valid()) 894 dict->Set("effective", proxy_service->config().ToValue()); 895 896 CallJavascriptFunction(L"g_browser.receivedProxySettings", dict); 897 } 898 899 void NetInternalsMessageHandler::IOThreadImpl::OnReloadProxySettings( 900 const ListValue* list) { 901 net::URLRequestContext* context = context_getter_->GetURLRequestContext(); 902 context->proxy_service()->ForceReloadProxyConfig(); 903 904 // Cause the renderer to be notified of the new values. 905 OnGetProxySettings(NULL); 906 } 907 908 void NetInternalsMessageHandler::IOThreadImpl::OnGetBadProxies( 909 const ListValue* list) { 910 net::URLRequestContext* context = context_getter_->GetURLRequestContext(); 911 912 const net::ProxyRetryInfoMap& bad_proxies_map = 913 context->proxy_service()->proxy_retry_info(); 914 915 ListValue* dict_list = new ListValue(); 916 917 for (net::ProxyRetryInfoMap::const_iterator it = bad_proxies_map.begin(); 918 it != bad_proxies_map.end(); ++it) { 919 const std::string& proxy_uri = it->first; 920 const net::ProxyRetryInfo& retry_info = it->second; 921 922 DictionaryValue* dict = new DictionaryValue(); 923 dict->SetString("proxy_uri", proxy_uri); 924 dict->SetString("bad_until", 925 net::NetLog::TickCountToString(retry_info.bad_until)); 926 927 dict_list->Append(dict); 928 } 929 930 CallJavascriptFunction(L"g_browser.receivedBadProxies", dict_list); 931 } 932 933 void NetInternalsMessageHandler::IOThreadImpl::OnClearBadProxies( 934 const ListValue* list) { 935 net::URLRequestContext* context = context_getter_->GetURLRequestContext(); 936 context->proxy_service()->ClearBadProxiesCache(); 937 938 // Cause the renderer to be notified of the new values. 939 OnGetBadProxies(NULL); 940 } 941 942 void NetInternalsMessageHandler::IOThreadImpl::OnGetHostResolverInfo( 943 const ListValue* list) { 944 net::URLRequestContext* context = context_getter_->GetURLRequestContext(); 945 net::HostResolverImpl* host_resolver_impl = 946 context->host_resolver()->GetAsHostResolverImpl(); 947 net::HostCache* cache = GetHostResolverCache(context); 948 949 if (!host_resolver_impl || !cache) { 950 CallJavascriptFunction(L"g_browser.receivedHostResolverInfo", NULL); 951 return; 952 } 953 954 DictionaryValue* dict = new DictionaryValue(); 955 956 dict->SetInteger( 957 "default_address_family", 958 static_cast<int>(host_resolver_impl->GetDefaultAddressFamily())); 959 960 DictionaryValue* cache_info_dict = new DictionaryValue(); 961 962 cache_info_dict->SetInteger( 963 "capacity", 964 static_cast<int>(cache->max_entries())); 965 cache_info_dict->SetInteger( 966 "ttl_success_ms", 967 static_cast<int>(cache->success_entry_ttl().InMilliseconds())); 968 cache_info_dict->SetInteger( 969 "ttl_failure_ms", 970 static_cast<int>(cache->failure_entry_ttl().InMilliseconds())); 971 972 ListValue* entry_list = new ListValue(); 973 974 for (net::HostCache::EntryMap::const_iterator it = 975 cache->entries().begin(); 976 it != cache->entries().end(); 977 ++it) { 978 const net::HostCache::Key& key = it->first; 979 const net::HostCache::Entry* entry = it->second.get(); 980 981 DictionaryValue* entry_dict = new DictionaryValue(); 982 983 entry_dict->SetString("hostname", key.hostname); 984 entry_dict->SetInteger("address_family", 985 static_cast<int>(key.address_family)); 986 entry_dict->SetString("expiration", 987 net::NetLog::TickCountToString(entry->expiration)); 988 989 if (entry->error != net::OK) { 990 entry_dict->SetInteger("error", entry->error); 991 } else { 992 // Append all of the resolved addresses. 993 ListValue* address_list = new ListValue(); 994 const struct addrinfo* current_address = entry->addrlist.head(); 995 while (current_address) { 996 address_list->Append(Value::CreateStringValue( 997 net::NetAddressToStringWithPort(current_address))); 998 current_address = current_address->ai_next; 999 } 1000 entry_dict->Set("addresses", address_list); 1001 } 1002 1003 entry_list->Append(entry_dict); 1004 } 1005 1006 cache_info_dict->Set("entries", entry_list); 1007 dict->Set("cache", cache_info_dict); 1008 1009 CallJavascriptFunction(L"g_browser.receivedHostResolverInfo", dict); 1010 } 1011 1012 void NetInternalsMessageHandler::IOThreadImpl::OnClearHostResolverCache( 1013 const ListValue* list) { 1014 net::HostCache* cache = 1015 GetHostResolverCache(context_getter_->GetURLRequestContext()); 1016 1017 if (cache) 1018 cache->clear(); 1019 1020 // Cause the renderer to be notified of the new values. 1021 OnGetHostResolverInfo(NULL); 1022 } 1023 1024 void NetInternalsMessageHandler::IOThreadImpl::OnEnableIPv6( 1025 const ListValue* list) { 1026 net::URLRequestContext* context = context_getter_->GetURLRequestContext(); 1027 net::HostResolverImpl* host_resolver_impl = 1028 context->host_resolver()->GetAsHostResolverImpl(); 1029 1030 if (host_resolver_impl) { 1031 host_resolver_impl->SetDefaultAddressFamily( 1032 net::ADDRESS_FAMILY_UNSPECIFIED); 1033 } 1034 1035 // Cause the renderer to be notified of the new value. 1036 OnGetHostResolverInfo(NULL); 1037 } 1038 1039 void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTests( 1040 const ListValue* list) { 1041 // |value| should be: [<URL to test>]. 1042 string16 url_str; 1043 CHECK(list->GetString(0, &url_str)); 1044 1045 // Try to fix-up the user provided URL into something valid. 1046 // For example, turn "www.google.com" into "http://www.google.com". 1047 GURL url(URLFixerUpper::FixupURL(UTF16ToUTF8(url_str), std::string())); 1048 1049 connection_tester_.reset(new ConnectionTester( 1050 this, io_thread_->globals()->proxy_script_fetcher_context.get())); 1051 connection_tester_->RunAllTests(url); 1052 } 1053 1054 void NetInternalsMessageHandler::IOThreadImpl::OnHSTSQuery( 1055 const ListValue* list) { 1056 // |list| should be: [<domain to query>]. 1057 std::string domain; 1058 CHECK(list->GetString(0, &domain)); 1059 DictionaryValue* result = new(DictionaryValue); 1060 1061 if (!IsStringASCII(domain)) { 1062 result->SetString("error", "non-ASCII domain name"); 1063 } else { 1064 net::TransportSecurityState* transport_security_state = 1065 context_getter_->GetURLRequestContext()->transport_security_state(); 1066 if (!transport_security_state) { 1067 result->SetString("error", "no TransportSecurityState active"); 1068 } else { 1069 net::TransportSecurityState::DomainState state; 1070 const bool found = transport_security_state->IsEnabledForHost( 1071 &state, domain, true); 1072 1073 result->SetBoolean("result", found); 1074 if (found) { 1075 result->SetInteger("mode", static_cast<int>(state.mode)); 1076 result->SetBoolean("subdomains", state.include_subdomains); 1077 result->SetBoolean("preloaded", state.preloaded); 1078 result->SetString("domain", state.domain); 1079 1080 std::vector<std::string> parts; 1081 for (std::vector<net::SHA1Fingerprint>::const_iterator 1082 i = state.public_key_hashes.begin(); 1083 i != state.public_key_hashes.end(); i++) { 1084 std::string part = "sha1/"; 1085 std::string hash_str(reinterpret_cast<const char*>(i->data), 1086 sizeof(i->data)); 1087 std::string b64; 1088 base::Base64Encode(hash_str, &b64); 1089 part += b64; 1090 parts.push_back(part); 1091 } 1092 result->SetString("public_key_hashes", JoinString(parts, ',')); 1093 } 1094 } 1095 } 1096 1097 CallJavascriptFunction(L"g_browser.receivedHSTSResult", result); 1098 } 1099 1100 void NetInternalsMessageHandler::IOThreadImpl::OnHSTSAdd( 1101 const ListValue* list) { 1102 // |list| should be: [<domain to query>, <include subdomains>, <cert pins>]. 1103 std::string domain; 1104 CHECK(list->GetString(0, &domain)); 1105 if (!IsStringASCII(domain)) { 1106 // Silently fail. The user will get a helpful error if they query for the 1107 // name. 1108 return; 1109 } 1110 bool include_subdomains; 1111 CHECK(list->GetBoolean(1, &include_subdomains)); 1112 std::string hashes_str; 1113 CHECK(list->GetString(2, &hashes_str)); 1114 1115 net::TransportSecurityState* transport_security_state = 1116 context_getter_->GetURLRequestContext()->transport_security_state(); 1117 if (!transport_security_state) 1118 return; 1119 1120 net::TransportSecurityState::DomainState state; 1121 state.expiry = state.created + base::TimeDelta::FromDays(1000); 1122 state.include_subdomains = include_subdomains; 1123 state.public_key_hashes.clear(); 1124 if (!hashes_str.empty()) { 1125 std::vector<std::string> type_and_b64s; 1126 base::SplitString(hashes_str, ',', &type_and_b64s); 1127 for (std::vector<std::string>::const_iterator 1128 i = type_and_b64s.begin(); i != type_and_b64s.end(); i++) { 1129 std::string type_and_b64; 1130 RemoveChars(*i, " \t\r\n", &type_and_b64); 1131 if (type_and_b64.find("sha1/") != 0) 1132 continue; 1133 std::string b64 = type_and_b64.substr(5, type_and_b64.size() - 5); 1134 std::string hash_str; 1135 if (!base::Base64Decode(b64, &hash_str)) 1136 continue; 1137 net::SHA1Fingerprint hash; 1138 if (hash_str.size() != sizeof(hash.data)) 1139 continue; 1140 memcpy(hash.data, hash_str.data(), sizeof(hash.data)); 1141 state.public_key_hashes.push_back(hash); 1142 } 1143 } 1144 1145 transport_security_state->EnableHost(domain, state); 1146 } 1147 1148 void NetInternalsMessageHandler::IOThreadImpl::OnHSTSDelete( 1149 const ListValue* list) { 1150 // |list| should be: [<domain to query>]. 1151 std::string domain; 1152 CHECK(list->GetString(0, &domain)); 1153 if (!IsStringASCII(domain)) { 1154 // There cannot be a unicode entry in the HSTS set. 1155 return; 1156 } 1157 net::TransportSecurityState* transport_security_state = 1158 context_getter_->GetURLRequestContext()->transport_security_state(); 1159 if (!transport_security_state) 1160 return; 1161 1162 transport_security_state->DeleteHost(domain); 1163 } 1164 1165 void NetInternalsMessageHandler::IOThreadImpl::OnGetHttpCacheInfo( 1166 const ListValue* list) { 1167 DictionaryValue* info_dict = new DictionaryValue(); 1168 DictionaryValue* stats_dict = new DictionaryValue(); 1169 1170 disk_cache::Backend* disk_cache = GetDiskCacheBackend( 1171 context_getter_->GetURLRequestContext()); 1172 1173 if (disk_cache) { 1174 // Extract the statistics key/value pairs from the backend. 1175 std::vector<std::pair<std::string, std::string> > stats; 1176 disk_cache->GetStats(&stats); 1177 for (size_t i = 0; i < stats.size(); ++i) { 1178 stats_dict->Set(stats[i].first, 1179 Value::CreateStringValue(stats[i].second)); 1180 } 1181 } 1182 1183 info_dict->Set("stats", stats_dict); 1184 1185 CallJavascriptFunction(L"g_browser.receivedHttpCacheInfo", info_dict); 1186 } 1187 1188 void NetInternalsMessageHandler::IOThreadImpl::OnGetSocketPoolInfo( 1189 const ListValue* list) { 1190 net::HttpNetworkSession* http_network_session = 1191 GetHttpNetworkSession(context_getter_->GetURLRequestContext()); 1192 1193 Value* socket_pool_info = NULL; 1194 if (http_network_session) 1195 socket_pool_info = http_network_session->SocketPoolInfoToValue(); 1196 1197 CallJavascriptFunction(L"g_browser.receivedSocketPoolInfo", socket_pool_info); 1198 } 1199 1200 1201 void NetInternalsMessageHandler::IOThreadImpl::OnFlushSocketPools( 1202 const ListValue* list) { 1203 net::HttpNetworkSession* http_network_session = 1204 GetHttpNetworkSession(context_getter_->GetURLRequestContext()); 1205 1206 if (http_network_session) 1207 http_network_session->CloseAllConnections(); 1208 } 1209 1210 void NetInternalsMessageHandler::IOThreadImpl::OnCloseIdleSockets( 1211 const ListValue* list) { 1212 net::HttpNetworkSession* http_network_session = 1213 GetHttpNetworkSession(context_getter_->GetURLRequestContext()); 1214 1215 if (http_network_session) 1216 http_network_session->CloseIdleConnections(); 1217 } 1218 1219 void NetInternalsMessageHandler::IOThreadImpl::OnGetSpdySessionInfo( 1220 const ListValue* list) { 1221 net::HttpNetworkSession* http_network_session = 1222 GetHttpNetworkSession(context_getter_->GetURLRequestContext()); 1223 1224 Value* spdy_info = NULL; 1225 if (http_network_session) { 1226 spdy_info = http_network_session->SpdySessionPoolInfoToValue(); 1227 } 1228 1229 CallJavascriptFunction(L"g_browser.receivedSpdySessionInfo", spdy_info); 1230 } 1231 1232 void NetInternalsMessageHandler::IOThreadImpl::OnGetSpdyStatus( 1233 const ListValue* list) { 1234 DictionaryValue* status_dict = new DictionaryValue(); 1235 1236 status_dict->Set("spdy_enabled", 1237 Value::CreateBooleanValue( 1238 net::HttpStreamFactory::spdy_enabled())); 1239 status_dict->Set("use_alternate_protocols", 1240 Value::CreateBooleanValue( 1241 net::HttpStreamFactory::use_alternate_protocols())); 1242 status_dict->Set("force_spdy_over_ssl", 1243 Value::CreateBooleanValue( 1244 net::HttpStreamFactory::force_spdy_over_ssl())); 1245 status_dict->Set("force_spdy_always", 1246 Value::CreateBooleanValue( 1247 net::HttpStreamFactory::force_spdy_always())); 1248 status_dict->Set("next_protos", 1249 Value::CreateStringValue( 1250 *net::HttpStreamFactory::next_protos())); 1251 1252 CallJavascriptFunction(L"g_browser.receivedSpdyStatus", status_dict); 1253 } 1254 1255 void 1256 NetInternalsMessageHandler::IOThreadImpl::OnGetSpdyAlternateProtocolMappings( 1257 const ListValue* list) { 1258 net::HttpNetworkSession* http_network_session = 1259 GetHttpNetworkSession(context_getter_->GetURLRequestContext()); 1260 1261 ListValue* dict_list = new ListValue(); 1262 1263 if (http_network_session) { 1264 const net::HttpAlternateProtocols& http_alternate_protocols = 1265 http_network_session->alternate_protocols(); 1266 const net::HttpAlternateProtocols::ProtocolMap& map = 1267 http_alternate_protocols.protocol_map(); 1268 1269 for (net::HttpAlternateProtocols::ProtocolMap::const_iterator it = 1270 map.begin(); 1271 it != map.end(); ++it) { 1272 DictionaryValue* dict = new DictionaryValue(); 1273 dict->SetString("host_port_pair", it->first.ToString()); 1274 dict->SetString("alternate_protocol", it->second.ToString()); 1275 dict_list->Append(dict); 1276 } 1277 } 1278 1279 CallJavascriptFunction(L"g_browser.receivedSpdyAlternateProtocolMappings", 1280 dict_list); 1281 } 1282 1283 #ifdef OS_WIN 1284 void NetInternalsMessageHandler::IOThreadImpl::OnGetServiceProviders( 1285 const ListValue* list) { 1286 1287 DictionaryValue* service_providers = new DictionaryValue(); 1288 1289 WinsockLayeredServiceProviderList layered_providers; 1290 GetWinsockLayeredServiceProviders(&layered_providers); 1291 ListValue* layered_provider_list = new ListValue(); 1292 for (size_t i = 0; i < layered_providers.size(); ++i) { 1293 DictionaryValue* service_dict = new DictionaryValue(); 1294 service_dict->SetString("name", layered_providers[i].name); 1295 service_dict->SetInteger("version", layered_providers[i].version); 1296 service_dict->SetInteger("chain_length", layered_providers[i].chain_length); 1297 service_dict->SetInteger("socket_type", layered_providers[i].socket_type); 1298 service_dict->SetInteger("socket_protocol", 1299 layered_providers[i].socket_protocol); 1300 service_dict->SetString("path", layered_providers[i].path); 1301 1302 layered_provider_list->Append(service_dict); 1303 } 1304 service_providers->Set("service_providers", layered_provider_list); 1305 1306 WinsockNamespaceProviderList namespace_providers; 1307 GetWinsockNamespaceProviders(&namespace_providers); 1308 ListValue* namespace_list = new ListValue; 1309 for (size_t i = 0; i < namespace_providers.size(); ++i) { 1310 DictionaryValue* namespace_dict = new DictionaryValue(); 1311 namespace_dict->SetString("name", namespace_providers[i].name); 1312 namespace_dict->SetBoolean("active", namespace_providers[i].active); 1313 namespace_dict->SetInteger("version", namespace_providers[i].version); 1314 namespace_dict->SetInteger("type", namespace_providers[i].type); 1315 1316 namespace_list->Append(namespace_dict); 1317 } 1318 service_providers->Set("namespace_providers", namespace_list); 1319 1320 CallJavascriptFunction(L"g_browser.receivedServiceProviders", 1321 service_providers); 1322 } 1323 #endif 1324 1325 void NetInternalsMessageHandler::IOThreadImpl::OnSetLogLevel( 1326 const ListValue* list) { 1327 int log_level; 1328 std::string log_level_string; 1329 if (!list->GetString(0, &log_level_string) || 1330 !base::StringToInt(log_level_string, &log_level)) { 1331 NOTREACHED(); 1332 return; 1333 } 1334 1335 DCHECK_GE(log_level, net::NetLog::LOG_ALL); 1336 DCHECK_LE(log_level, net::NetLog::LOG_BASIC); 1337 SetLogLevel(static_cast<net::NetLog::LogLevel>(log_level)); 1338 } 1339 1340 // Note that unlike other methods of IOThreadImpl, this function 1341 // can be called from ANY THREAD. 1342 void NetInternalsMessageHandler::IOThreadImpl::OnAddEntry( 1343 net::NetLog::EventType type, 1344 const base::TimeTicks& time, 1345 const net::NetLog::Source& source, 1346 net::NetLog::EventPhase phase, 1347 net::NetLog::EventParameters* params) { 1348 BrowserThread::PostTask( 1349 BrowserThread::IO, FROM_HERE, 1350 NewRunnableMethod( 1351 this, &IOThreadImpl::AddEntryToQueue, 1352 net::NetLog::EntryToDictionaryValue(type, time, source, phase, 1353 params, false))); 1354 } 1355 1356 void NetInternalsMessageHandler::IOThreadImpl::AddEntryToQueue(Value* entry) { 1357 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1358 if (!pending_entries_.get()) { 1359 pending_entries_.reset(new ListValue()); 1360 BrowserThread::PostDelayedTask( 1361 BrowserThread::IO, FROM_HERE, 1362 NewRunnableMethod(this, &IOThreadImpl::PostPendingEntries), 1363 kNetLogEventDelayMilliseconds); 1364 } 1365 pending_entries_->Append(entry); 1366 } 1367 1368 void NetInternalsMessageHandler::IOThreadImpl::PostPendingEntries() { 1369 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1370 CallJavascriptFunction( 1371 L"g_browser.receivedLogEntries", 1372 pending_entries_.release()); 1373 } 1374 1375 void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTestSuite() { 1376 CallJavascriptFunction(L"g_browser.receivedStartConnectionTestSuite", NULL); 1377 } 1378 1379 void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTestExperiment( 1380 const ConnectionTester::Experiment& experiment) { 1381 CallJavascriptFunction( 1382 L"g_browser.receivedStartConnectionTestExperiment", 1383 ExperimentToValue(experiment)); 1384 } 1385 1386 void 1387 NetInternalsMessageHandler::IOThreadImpl::OnCompletedConnectionTestExperiment( 1388 const ConnectionTester::Experiment& experiment, 1389 int result) { 1390 DictionaryValue* dict = new DictionaryValue(); 1391 1392 dict->Set("experiment", ExperimentToValue(experiment)); 1393 dict->SetInteger("result", result); 1394 1395 CallJavascriptFunction( 1396 L"g_browser.receivedCompletedConnectionTestExperiment", 1397 dict); 1398 } 1399 1400 void 1401 NetInternalsMessageHandler::IOThreadImpl::OnCompletedConnectionTestSuite() { 1402 CallJavascriptFunction( 1403 L"g_browser.receivedCompletedConnectionTestSuite", 1404 NULL); 1405 } 1406 1407 void NetInternalsMessageHandler::IOThreadImpl::DispatchToMessageHandler( 1408 ListValue* arg, MessageHandler method) { 1409 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1410 (this->*method)(arg); 1411 delete arg; 1412 } 1413 1414 // Note that this can be called from ANY THREAD. 1415 void NetInternalsMessageHandler::IOThreadImpl::CallJavascriptFunction( 1416 const std::wstring& function_name, 1417 Value* arg) { 1418 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { 1419 if (handler_ && !was_webui_deleted_) { 1420 // We check |handler_| in case it was deleted on the UI thread earlier 1421 // while we were running on the IO thread. 1422 handler_->CallJavascriptFunction(function_name, arg); 1423 } 1424 delete arg; 1425 return; 1426 } 1427 1428 if (!BrowserThread::PostTask( 1429 BrowserThread::UI, FROM_HERE, 1430 NewRunnableMethod( 1431 this, 1432 &IOThreadImpl::CallJavascriptFunction, 1433 function_name, arg))) { 1434 // Failed posting the task, avoid leaking. 1435 delete arg; 1436 } 1437 } 1438 1439 } // namespace 1440 1441 1442 //////////////////////////////////////////////////////////////////////////////// 1443 // 1444 // NetInternalsUI 1445 // 1446 //////////////////////////////////////////////////////////////////////////////// 1447 1448 NetInternalsUI::NetInternalsUI(TabContents* contents) : WebUI(contents) { 1449 AddMessageHandler((new NetInternalsMessageHandler())->Attach(this)); 1450 1451 NetInternalsHTMLSource* html_source = new NetInternalsHTMLSource(); 1452 1453 // Set up the chrome://net-internals/ source. 1454 contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source); 1455 } 1456