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.
5 #include "chrome/browser/ui/webui/net_internals/net_internals_ui.h"
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.h"
19 #include "base/files/file_path.h"
20 #include "base/memory/weak_ptr.h"
21 #include "base/message_loop/message_loop.h"
22 #include "base/prefs/pref_member.h"
23 #include "base/sequenced_task_runner_helpers.h"
24 #include "base/strings/string_number_conversions.h"
25 #include "base/strings/string_piece.h"
26 #include "base/strings/string_split.h"
27 #include "base/strings/string_util.h"
28 #include "base/strings/utf_string_conversions.h"
29 #include "base/task/cancelable_task_tracker.h"
30 #include "base/values.h"
31 #include "chrome/browser/browser_process.h"
32 #include "chrome/browser/browsing_data/browsing_data_helper.h"
33 #include "chrome/browser/browsing_data/browsing_data_remover.h"
34 #include "chrome/browser/chrome_notification_types.h"
35 #include "chrome/browser/download/download_prefs.h"
36 #include "chrome/browser/io_thread.h"
37 #include "chrome/browser/net/chrome_net_log.h"
38 #include "chrome/browser/net/chrome_network_delegate.h"
39 #include "chrome/browser/net/connection_tester.h"
40 #include "chrome/browser/prerender/prerender_manager.h"
41 #include "chrome/browser/prerender/prerender_manager_factory.h"
42 #include "chrome/browser/profiles/profile.h"
43 #include "chrome/common/chrome_paths.h"
44 #include "chrome/common/chrome_version_info.h"
45 #include "chrome/common/pref_names.h"
46 #include "chrome/common/url_constants.h"
47 #include "components/onc/onc_constants.h"
48 #include "components/url_fixer/url_fixer.h"
49 #include "content/public/browser/browser_thread.h"
50 #include "content/public/browser/notification_details.h"
51 #include "content/public/browser/resource_dispatcher_host.h"
52 #include "content/public/browser/web_contents.h"
53 #include "content/public/browser/web_ui.h"
54 #include "content/public/browser/web_ui_data_source.h"
55 #include "content/public/browser/web_ui_message_handler.h"
56 #include "grit/generated_resources.h"
57 #include "grit/net_internals_resources.h"
58 #include "net/base/net_errors.h"
59 #include "net/base/net_log_logger.h"
60 #include "net/base/net_util.h"
61 #include "net/disk_cache/disk_cache.h"
62 #include "net/dns/host_cache.h"
63 #include "net/dns/host_resolver.h"
64 #include "net/http/http_cache.h"
65 #include "net/http/http_network_layer.h"
66 #include "net/http/http_network_session.h"
67 #include "net/http/http_server_properties.h"
68 #include "net/http/http_stream_factory.h"
69 #include "net/http/transport_security_state.h"
70 #include "net/proxy/proxy_service.h"
71 #include "net/url_request/url_request_context.h"
72 #include "net/url_request/url_request_context_getter.h"
74 #if defined(OS_CHROMEOS)
75 #include "chrome/browser/chromeos/file_manager/filesystem_api_util.h"
76 #include "chrome/browser/chromeos/net/onc_utils.h"
77 #include "chrome/browser/chromeos/profiles/profile_helper.h"
78 #include "chrome/browser/chromeos/system/syslogs_provider.h"
79 #include "chrome/browser/chromeos/system_logs/debug_log_writer.h"
80 #include "chrome/browser/net/nss_context.h"
81 #include "chromeos/dbus/dbus_thread_manager.h"
82 #include "chromeos/dbus/debug_daemon_client.h"
83 #include "chromeos/network/onc/onc_certificate_importer_impl.h"
84 #include "chromeos/network/onc/onc_utils.h"
85 #include "components/user_manager/user.h"
89 #include "chrome/browser/net/service_providers_win.h"
92 #if defined(ENABLE_EXTENSIONS)
93 #include "chrome/browser/extensions/extension_service.h"
94 #include "chrome/browser/ui/webui/extensions/extension_basic_info.h"
95 #include "extensions/browser/extension_registry.h"
96 #include "extensions/browser/extension_system.h"
97 #include "extensions/common/extension_set.h"
100 using base::StringValue;
101 using content::BrowserThread;
102 using content::WebContents;
103 using content::WebUIMessageHandler;
107 // Delay between when an event occurs and when it is passed to the Javascript
108 // page. All events that occur during this period are grouped together and
109 // sent to the page at once, which reduces context switching and CPU usage.
110 const int kNetLogEventDelayMilliseconds = 100;
112 // Returns the HostCache for |context|'s primary HostResolver, or NULL if
114 net::HostCache* GetHostResolverCache(net::URLRequestContext* context) {
115 return context->host_resolver()->GetHostCache();
118 std::string HashesToBase64String(const net::HashValueVector& hashes) {
120 for (size_t i = 0; i != hashes.size(); ++i) {
123 str += hashes[i].ToString();
128 bool Base64StringToHashes(const std::string& hashes_str,
129 net::HashValueVector* hashes) {
131 std::vector<std::string> vector_hash_str;
132 base::SplitString(hashes_str, ',', &vector_hash_str);
134 for (size_t i = 0; i != vector_hash_str.size(); ++i) {
135 std::string hash_str;
136 base::RemoveChars(vector_hash_str[i], " \t\r\n", &hash_str);
138 // Skip past unrecognized hash algos
139 // But return false on malformatted input
140 if (hash_str.empty())
142 if (hash_str.compare(0, 5, "sha1/") != 0 &&
143 hash_str.compare(0, 7, "sha256/") != 0) {
146 if (!hash.FromString(hash_str))
148 hashes->push_back(hash);
153 // Returns a Value representing the state of a pre-existing URLRequest when
154 // net-internals was opened.
155 base::Value* GetRequestStateAsValue(const net::URLRequest* request,
156 net::NetLog::LogLevel log_level) {
157 return request->GetStateAsValue();
160 // Returns true if |request1| was created before |request2|.
161 bool RequestCreatedBefore(const net::URLRequest* request1,
162 const net::URLRequest* request2) {
163 return request1->creation_time() < request2->creation_time();
166 // Returns the disk cache backend for |context| if there is one, or NULL.
167 disk_cache::Backend* GetDiskCacheBackend(net::URLRequestContext* context) {
168 if (!context->http_transaction_factory())
171 net::HttpCache* http_cache = context->http_transaction_factory()->GetCache();
175 return http_cache->GetCurrentBackend();
178 // Returns the http network session for |context| if there is one.
179 // Otherwise, returns NULL.
180 net::HttpNetworkSession* GetHttpNetworkSession(
181 net::URLRequestContext* context) {
182 if (!context->http_transaction_factory())
185 return context->http_transaction_factory()->GetSession();
188 base::Value* ExperimentToValue(const ConnectionTester::Experiment& experiment) {
189 base::DictionaryValue* dict = new base::DictionaryValue();
191 if (experiment.url.is_valid())
192 dict->SetString("url", experiment.url.spec());
194 dict->SetString("proxy_settings_experiment",
195 ConnectionTester::ProxySettingsExperimentDescription(
196 experiment.proxy_settings_experiment));
197 dict->SetString("host_resolver_experiment",
198 ConnectionTester::HostResolverExperimentDescription(
199 experiment.host_resolver_experiment));
203 content::WebUIDataSource* CreateNetInternalsHTMLSource() {
204 content::WebUIDataSource* source =
205 content::WebUIDataSource::Create(chrome::kChromeUINetInternalsHost);
207 source->SetUseJsonJSFormatV2();
208 source->SetDefaultResource(IDR_NET_INTERNALS_INDEX_HTML);
209 source->AddResourcePath("index.js", IDR_NET_INTERNALS_INDEX_JS);
210 source->SetJsonPath("strings.js");
214 // This class receives javascript messages from the renderer.
215 // Note that the WebUI infrastructure runs on the UI thread, therefore all of
216 // this class's methods are expected to run on the UI thread.
218 // Since the network code we want to run lives on the IO thread, we proxy
219 // almost everything over to NetInternalsMessageHandler::IOThreadImpl, which
220 // runs on the IO thread.
222 // TODO(eroman): Can we start on the IO thread to begin with?
223 class NetInternalsMessageHandler
224 : public WebUIMessageHandler,
225 public base::SupportsWeakPtr<NetInternalsMessageHandler> {
227 NetInternalsMessageHandler();
228 virtual ~NetInternalsMessageHandler();
230 // WebUIMessageHandler implementation.
231 virtual void RegisterMessages() OVERRIDE;
233 // Calls g_browser.receive in the renderer, passing in |command| and |arg|.
234 // Takes ownership of |arg|. If the renderer is displaying a log file, the
235 // message will be ignored.
236 void SendJavascriptCommand(const std::string& command, base::Value* arg);
238 // Javascript message handlers.
239 void OnRendererReady(const base::ListValue* list);
240 void OnClearBrowserCache(const base::ListValue* list);
241 void OnGetPrerenderInfo(const base::ListValue* list);
242 void OnGetHistoricNetworkStats(const base::ListValue* list);
243 void OnGetExtensionInfo(const base::ListValue* list);
244 #if defined(OS_CHROMEOS)
245 void OnRefreshSystemLogs(const base::ListValue* list);
246 void OnGetSystemLog(const base::ListValue* list);
247 void OnImportONCFile(const base::ListValue* list);
248 void OnStoreDebugLogs(const base::ListValue* list);
249 void OnStoreDebugLogsCompleted(const base::FilePath& log_path,
251 void OnSetNetworkDebugMode(const base::ListValue* list);
252 void OnSetNetworkDebugModeCompleted(const std::string& subsystem,
255 // Callback to |GetNSSCertDatabaseForProfile| used to retrieve the database
256 // to which user's ONC defined certificates should be imported.
257 // It parses and imports |onc_blob|.
258 void ImportONCFileToNSSDB(const std::string& onc_blob,
259 const std::string& passcode,
260 net::NSSCertDatabase* nssdb);
266 #if defined(OS_CHROMEOS)
267 // Class that is used for getting network related ChromeOS logs.
268 // Logs are fetched from ChromeOS libcros on user request, and only when we
269 // don't yet have a copy of logs. If a copy is present, we send back data from
270 // it, else we save request and answer to it when we get logs from libcros.
271 // If needed, we also send request for system logs to libcros.
272 // Logs refresh has to be done explicitly, by deleting old logs and then
273 // loading them again.
274 class SystemLogsGetter {
276 SystemLogsGetter(NetInternalsMessageHandler* handler,
277 chromeos::system::SyslogsProvider* syslogs_provider);
280 // Deletes logs copy we currently have, and resets logs_requested and
281 // logs_received flags.
282 void DeleteSystemLogs();
283 // Starts log fetching. If logs copy is present, requested logs are sent
285 // If syslogs load request hasn't been sent to libcros yet, we do that now,
286 // and postpone sending response.
287 // Request data is specified by args:
288 // $1 : key of the log we are interested in.
289 // $2 : string used to identify request.
290 void RequestSystemLog(const base::ListValue* args);
291 // Requests logs from libcros, but only if we don't have a copy.
292 void LoadSystemLogs();
293 // Processes callback from libcros containing system logs. Postponed
294 // request responses are sent.
295 void OnSystemLogsLoaded(chromeos::system::LogDictionaryType* sys_info,
296 std::string* ignored_content);
299 // Struct we save postponed log request in.
300 struct SystemLogRequest {
305 // Processes request.
306 void SendLogs(const SystemLogRequest& request);
308 NetInternalsMessageHandler* handler_;
309 chromeos::system::SyslogsProvider* syslogs_provider_;
310 // List of postponed requests.
311 std::list<SystemLogRequest> requests_;
312 scoped_ptr<chromeos::system::LogDictionaryType> logs_;
314 bool logs_requested_;
315 base::CancelableTaskTracker tracker_;
316 // Libcros request task ID.
317 base::CancelableTaskTracker::TaskId syslogs_task_id_;
319 #endif // defined(OS_CHROMEOS)
321 // This is the "real" message handler, which lives on the IO thread.
322 scoped_refptr<IOThreadImpl> proxy_;
324 base::WeakPtr<prerender::PrerenderManager> prerender_manager_;
326 #if defined(OS_CHROMEOS)
327 // Class that handles getting and filtering system logs.
328 scoped_ptr<SystemLogsGetter> syslogs_getter_;
331 DISALLOW_COPY_AND_ASSIGN(NetInternalsMessageHandler);
334 // This class is the "real" message handler. It is allocated and destroyed on
335 // the UI thread. With the exception of OnAddEntry, OnWebUIDeleted, and
336 // SendJavascriptCommand, its methods are all expected to be called from the IO
337 // thread. OnAddEntry and SendJavascriptCommand can be called from any thread,
338 // and OnWebUIDeleted can only be called from the UI thread.
339 class NetInternalsMessageHandler::IOThreadImpl
340 : public base::RefCountedThreadSafe<
341 NetInternalsMessageHandler::IOThreadImpl,
342 BrowserThread::DeleteOnUIThread>,
343 public net::NetLog::ThreadSafeObserver,
344 public ConnectionTester::Delegate {
346 // Type for methods that can be used as MessageHandler callbacks.
347 typedef void (IOThreadImpl::*MessageHandler)(const base::ListValue*);
349 // Creates a proxy for |handler| that will live on the IO thread.
350 // |handler| is a weak pointer, since it is possible for the
351 // WebUIMessageHandler to be deleted on the UI thread while we were executing
352 // on the IO thread. |io_thread| is the global IOThread (it is passed in as
353 // an argument since we need to grab it from the UI thread).
355 const base::WeakPtr<NetInternalsMessageHandler>& handler,
357 net::URLRequestContextGetter* main_context_getter);
359 // Called on UI thread just after creation, to add a ContextGetter to
360 // |context_getters_|.
361 void AddRequestContextGetter(net::URLRequestContextGetter* context_getter);
363 // Helper method to enable a callback that will be executed on the IO thread.
364 static void CallbackHelper(MessageHandler method,
365 scoped_refptr<IOThreadImpl> io_thread,
366 const base::ListValue* list);
368 // Called once the WebUI has been deleted (i.e. renderer went away), on the
372 // Called when the WebUI is deleted. Prevents calling Javascript functions
373 // afterwards. Called on UI thread.
374 void OnWebUIDeleted();
376 //--------------------------------
377 // Javascript message handlers:
378 //--------------------------------
380 void OnRendererReady(const base::ListValue* list);
382 void OnGetProxySettings(const base::ListValue* list);
383 void OnReloadProxySettings(const base::ListValue* list);
384 void OnGetBadProxies(const base::ListValue* list);
385 void OnClearBadProxies(const base::ListValue* list);
386 void OnGetHostResolverInfo(const base::ListValue* list);
387 void OnClearHostResolverCache(const base::ListValue* list);
388 void OnEnableIPv6(const base::ListValue* list);
389 void OnStartConnectionTests(const base::ListValue* list);
390 void OnHSTSQuery(const base::ListValue* list);
391 void OnHSTSAdd(const base::ListValue* list);
392 void OnHSTSDelete(const base::ListValue* list);
393 void OnGetHttpCacheInfo(const base::ListValue* list);
394 void OnGetSocketPoolInfo(const base::ListValue* list);
395 void OnGetSessionNetworkStats(const base::ListValue* list);
396 void OnCloseIdleSockets(const base::ListValue* list);
397 void OnFlushSocketPools(const base::ListValue* list);
398 void OnGetSpdySessionInfo(const base::ListValue* list);
399 void OnGetSpdyStatus(const base::ListValue* list);
400 void OnGetSpdyAlternateProtocolMappings(const base::ListValue* list);
401 void OnGetQuicInfo(const base::ListValue* list);
403 void OnGetServiceProviders(const base::ListValue* list);
405 void OnSetLogLevel(const base::ListValue* list);
407 // ChromeNetLog::ThreadSafeObserver implementation:
408 virtual void OnAddEntry(const net::NetLog::Entry& entry) OVERRIDE;
410 // ConnectionTester::Delegate implementation:
411 virtual void OnStartConnectionTestSuite() OVERRIDE;
412 virtual void OnStartConnectionTestExperiment(
413 const ConnectionTester::Experiment& experiment) OVERRIDE;
414 virtual void OnCompletedConnectionTestExperiment(
415 const ConnectionTester::Experiment& experiment,
416 int result) OVERRIDE;
417 virtual void OnCompletedConnectionTestSuite() OVERRIDE;
419 // Helper that calls g_browser.receive in the renderer, passing in |command|
420 // and |arg|. Takes ownership of |arg|. If the renderer is displaying a log
421 // file, the message will be ignored. Note that this can be called from any
423 void SendJavascriptCommand(const std::string& command, base::Value* arg);
426 friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>;
427 friend class base::DeleteHelper<IOThreadImpl>;
429 typedef std::list<scoped_refptr<net::URLRequestContextGetter> >
432 virtual ~IOThreadImpl();
434 // Adds |entry| to the queue of pending log entries to be sent to the page via
435 // Javascript. Must be called on the IO Thread. Also creates a delayed task
436 // that will call PostPendingEntries, if there isn't one already.
437 void AddEntryToQueue(base::Value* entry);
439 // Sends all pending entries to the page via Javascript, and clears the list
440 // of pending entries. Sending multiple entries at once results in a
441 // significant reduction of CPU usage when a lot of events are happening.
442 // Must be called on the IO Thread.
443 void PostPendingEntries();
445 // Adds entries with the states of ongoing URL requests.
446 void PrePopulateEventList();
448 net::URLRequestContext* GetMainContext() {
449 return main_context_getter_->GetURLRequestContext();
452 // Pointer to the UI-thread message handler. Only access this from
454 base::WeakPtr<NetInternalsMessageHandler> handler_;
456 // The global IOThread, which contains the global NetLog to observer.
457 IOThread* io_thread_;
459 // The main URLRequestContextGetter for the tab's profile.
460 scoped_refptr<net::URLRequestContextGetter> main_context_getter_;
462 // Helper that runs the suite of connection tests.
463 scoped_ptr<ConnectionTester> connection_tester_;
465 // True if the Web UI has been deleted. This is used to prevent calling
466 // Javascript functions after the Web UI is destroyed. On refresh, the
467 // messages can end up being sent to the refreshed page, causing duplicate
468 // or partial entries.
470 // This is only read and written to on the UI thread.
471 bool was_webui_deleted_;
473 // Log entries that have yet to be passed along to Javascript page. Non-NULL
474 // when and only when there is a pending delayed task to call
475 // PostPendingEntries. Read and written to exclusively on the IO Thread.
476 scoped_ptr<base::ListValue> pending_entries_;
478 // Used for getting current status of URLRequests when net-internals is
479 // opened. |main_context_getter_| is automatically added on construction.
480 // Duplicates are allowed.
481 ContextGetterList context_getters_;
483 DISALLOW_COPY_AND_ASSIGN(IOThreadImpl);
486 ////////////////////////////////////////////////////////////////////////////////
488 // NetInternalsMessageHandler
490 ////////////////////////////////////////////////////////////////////////////////
492 NetInternalsMessageHandler::NetInternalsMessageHandler() {}
494 NetInternalsMessageHandler::~NetInternalsMessageHandler() {
496 proxy_.get()->OnWebUIDeleted();
497 // Notify the handler on the IO thread that the renderer is gone.
498 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
499 base::Bind(&IOThreadImpl::Detach, proxy_.get()));
503 void NetInternalsMessageHandler::RegisterMessages() {
504 DCHECK_CURRENTLY_ON(BrowserThread::UI);
506 Profile* profile = Profile::FromWebUI(web_ui());
508 proxy_ = new IOThreadImpl(this->AsWeakPtr(), g_browser_process->io_thread(),
509 profile->GetRequestContext());
510 proxy_->AddRequestContextGetter(profile->GetMediaRequestContext());
511 proxy_->AddRequestContextGetter(profile->GetRequestContextForExtensions());
512 #if defined(OS_CHROMEOS)
513 syslogs_getter_.reset(new SystemLogsGetter(this,
514 chromeos::system::SyslogsProvider::GetInstance()));
517 prerender::PrerenderManager* prerender_manager =
518 prerender::PrerenderManagerFactory::GetForProfile(profile);
519 if (prerender_manager) {
520 prerender_manager_ = prerender_manager->AsWeakPtr();
522 prerender_manager_ = base::WeakPtr<prerender::PrerenderManager>();
525 web_ui()->RegisterMessageCallback(
527 base::Bind(&NetInternalsMessageHandler::OnRendererReady,
528 base::Unretained(this)));
529 web_ui()->RegisterMessageCallback(
531 base::Bind(&IOThreadImpl::CallbackHelper,
532 &IOThreadImpl::OnGetProxySettings, proxy_));
533 web_ui()->RegisterMessageCallback(
534 "reloadProxySettings",
535 base::Bind(&IOThreadImpl::CallbackHelper,
536 &IOThreadImpl::OnReloadProxySettings, proxy_));
537 web_ui()->RegisterMessageCallback(
539 base::Bind(&IOThreadImpl::CallbackHelper,
540 &IOThreadImpl::OnGetBadProxies, proxy_));
541 web_ui()->RegisterMessageCallback(
543 base::Bind(&IOThreadImpl::CallbackHelper,
544 &IOThreadImpl::OnClearBadProxies, proxy_));
545 web_ui()->RegisterMessageCallback(
546 "getHostResolverInfo",
547 base::Bind(&IOThreadImpl::CallbackHelper,
548 &IOThreadImpl::OnGetHostResolverInfo, proxy_));
549 web_ui()->RegisterMessageCallback(
550 "clearHostResolverCache",
551 base::Bind(&IOThreadImpl::CallbackHelper,
552 &IOThreadImpl::OnClearHostResolverCache, proxy_));
553 web_ui()->RegisterMessageCallback(
555 base::Bind(&IOThreadImpl::CallbackHelper,
556 &IOThreadImpl::OnEnableIPv6, proxy_));
557 web_ui()->RegisterMessageCallback(
558 "startConnectionTests",
559 base::Bind(&IOThreadImpl::CallbackHelper,
560 &IOThreadImpl::OnStartConnectionTests, proxy_));
561 web_ui()->RegisterMessageCallback(
563 base::Bind(&IOThreadImpl::CallbackHelper,
564 &IOThreadImpl::OnHSTSQuery, proxy_));
565 web_ui()->RegisterMessageCallback(
567 base::Bind(&IOThreadImpl::CallbackHelper,
568 &IOThreadImpl::OnHSTSAdd, proxy_));
569 web_ui()->RegisterMessageCallback(
571 base::Bind(&IOThreadImpl::CallbackHelper,
572 &IOThreadImpl::OnHSTSDelete, proxy_));
573 web_ui()->RegisterMessageCallback(
575 base::Bind(&IOThreadImpl::CallbackHelper,
576 &IOThreadImpl::OnGetHttpCacheInfo, proxy_));
577 web_ui()->RegisterMessageCallback(
579 base::Bind(&IOThreadImpl::CallbackHelper,
580 &IOThreadImpl::OnGetSocketPoolInfo, proxy_));
581 web_ui()->RegisterMessageCallback(
582 "getSessionNetworkStats",
583 base::Bind(&IOThreadImpl::CallbackHelper,
584 &IOThreadImpl::OnGetSessionNetworkStats, proxy_));
585 web_ui()->RegisterMessageCallback(
587 base::Bind(&IOThreadImpl::CallbackHelper,
588 &IOThreadImpl::OnCloseIdleSockets, proxy_));
589 web_ui()->RegisterMessageCallback(
591 base::Bind(&IOThreadImpl::CallbackHelper,
592 &IOThreadImpl::OnFlushSocketPools, proxy_));
593 web_ui()->RegisterMessageCallback(
594 "getSpdySessionInfo",
595 base::Bind(&IOThreadImpl::CallbackHelper,
596 &IOThreadImpl::OnGetSpdySessionInfo, proxy_));
597 web_ui()->RegisterMessageCallback(
599 base::Bind(&IOThreadImpl::CallbackHelper,
600 &IOThreadImpl::OnGetSpdyStatus, proxy_));
601 web_ui()->RegisterMessageCallback(
602 "getSpdyAlternateProtocolMappings",
603 base::Bind(&IOThreadImpl::CallbackHelper,
604 &IOThreadImpl::OnGetSpdyAlternateProtocolMappings, proxy_));
605 web_ui()->RegisterMessageCallback(
607 base::Bind(&IOThreadImpl::CallbackHelper,
608 &IOThreadImpl::OnGetQuicInfo, proxy_));
610 web_ui()->RegisterMessageCallback(
611 "getServiceProviders",
612 base::Bind(&IOThreadImpl::CallbackHelper,
613 &IOThreadImpl::OnGetServiceProviders, proxy_));
616 web_ui()->RegisterMessageCallback(
618 base::Bind(&IOThreadImpl::CallbackHelper,
619 &IOThreadImpl::OnSetLogLevel, proxy_));
620 web_ui()->RegisterMessageCallback(
622 base::Bind(&NetInternalsMessageHandler::OnClearBrowserCache,
623 base::Unretained(this)));
624 web_ui()->RegisterMessageCallback(
626 base::Bind(&NetInternalsMessageHandler::OnGetPrerenderInfo,
627 base::Unretained(this)));
628 web_ui()->RegisterMessageCallback(
629 "getHistoricNetworkStats",
630 base::Bind(&NetInternalsMessageHandler::OnGetHistoricNetworkStats,
631 base::Unretained(this)));
632 web_ui()->RegisterMessageCallback(
634 base::Bind(&NetInternalsMessageHandler::OnGetExtensionInfo,
635 base::Unretained(this)));
636 #if defined(OS_CHROMEOS)
637 web_ui()->RegisterMessageCallback(
639 base::Bind(&NetInternalsMessageHandler::OnRefreshSystemLogs,
640 base::Unretained(this)));
641 web_ui()->RegisterMessageCallback(
643 base::Bind(&NetInternalsMessageHandler::OnGetSystemLog,
644 base::Unretained(this)));
645 web_ui()->RegisterMessageCallback(
647 base::Bind(&NetInternalsMessageHandler::OnImportONCFile,
648 base::Unretained(this)));
649 web_ui()->RegisterMessageCallback(
651 base::Bind(&NetInternalsMessageHandler::OnStoreDebugLogs,
652 base::Unretained(this)));
653 web_ui()->RegisterMessageCallback(
654 "setNetworkDebugMode",
655 base::Bind(&NetInternalsMessageHandler::OnSetNetworkDebugMode,
656 base::Unretained(this)));
660 void NetInternalsMessageHandler::SendJavascriptCommand(
661 const std::string& command,
663 scoped_ptr<base::Value> command_value(new base::StringValue(command));
664 scoped_ptr<base::Value> value(arg);
665 DCHECK_CURRENTLY_ON(BrowserThread::UI);
667 web_ui()->CallJavascriptFunction("g_browser.receive",
668 *command_value.get(),
671 web_ui()->CallJavascriptFunction("g_browser.receive",
672 *command_value.get());
676 void NetInternalsMessageHandler::OnRendererReady(const base::ListValue* list) {
677 IOThreadImpl::CallbackHelper(&IOThreadImpl::OnRendererReady, proxy_, list);
680 void NetInternalsMessageHandler::OnClearBrowserCache(
681 const base::ListValue* list) {
682 BrowsingDataRemover* remover = BrowsingDataRemover::CreateForUnboundedRange(
683 Profile::FromWebUI(web_ui()));
684 remover->Remove(BrowsingDataRemover::REMOVE_CACHE,
685 BrowsingDataHelper::UNPROTECTED_WEB);
686 // BrowsingDataRemover deletes itself.
689 void NetInternalsMessageHandler::OnGetPrerenderInfo(
690 const base::ListValue* list) {
691 DCHECK_CURRENTLY_ON(BrowserThread::UI);
693 base::DictionaryValue* value = NULL;
694 prerender::PrerenderManager* prerender_manager = prerender_manager_.get();
695 if (!prerender_manager) {
696 value = new base::DictionaryValue();
697 value->SetBoolean("enabled", false);
698 value->SetBoolean("omnibox_enabled", false);
700 value = prerender_manager->GetAsValue();
702 SendJavascriptCommand("receivedPrerenderInfo", value);
705 void NetInternalsMessageHandler::OnGetHistoricNetworkStats(
706 const base::ListValue* list) {
707 DCHECK_CURRENTLY_ON(BrowserThread::UI);
708 base::Value* historic_network_info =
709 ChromeNetworkDelegate::HistoricNetworkStatsInfoToValue();
710 SendJavascriptCommand("receivedHistoricNetworkStats", historic_network_info);
713 void NetInternalsMessageHandler::OnGetExtensionInfo(
714 const base::ListValue* list) {
715 DCHECK_CURRENTLY_ON(BrowserThread::UI);
716 base::ListValue* extension_list = new base::ListValue();
717 #if defined(ENABLE_EXTENSIONS)
718 Profile* profile = Profile::FromWebUI(web_ui());
719 extensions::ExtensionSystem* extension_system =
720 extensions::ExtensionSystem::Get(profile);
721 if (extension_system) {
722 ExtensionService* extension_service = extension_system->extension_service();
723 if (extension_service) {
724 scoped_ptr<const extensions::ExtensionSet> extensions(
725 extensions::ExtensionRegistry::Get(profile)
726 ->GenerateInstalledExtensionsSet());
727 for (extensions::ExtensionSet::const_iterator it = extensions->begin();
728 it != extensions->end(); ++it) {
729 base::DictionaryValue* extension_info = new base::DictionaryValue();
730 bool enabled = extension_service->IsExtensionEnabled((*it)->id());
731 extensions::GetExtensionBasicInfo(it->get(), enabled, extension_info);
732 extension_list->Append(extension_info);
737 SendJavascriptCommand("receivedExtensionInfo", extension_list);
740 #if defined(OS_CHROMEOS)
741 ////////////////////////////////////////////////////////////////////////////////
743 // NetInternalsMessageHandler::SystemLogsGetter
745 ////////////////////////////////////////////////////////////////////////////////
747 NetInternalsMessageHandler::SystemLogsGetter::SystemLogsGetter(
748 NetInternalsMessageHandler* handler,
749 chromeos::system::SyslogsProvider* syslogs_provider)
751 syslogs_provider_(syslogs_provider),
752 logs_received_(false),
753 logs_requested_(false) {
754 if (!syslogs_provider_)
755 LOG(ERROR) << "System access library not loaded";
758 NetInternalsMessageHandler::SystemLogsGetter::~SystemLogsGetter() {
762 void NetInternalsMessageHandler::SystemLogsGetter::DeleteSystemLogs() {
763 if (syslogs_provider_ && logs_requested_ && !logs_received_) {
764 tracker_.TryCancel(syslogs_task_id_);
766 logs_requested_ = false;
767 logs_received_ = false;
771 void NetInternalsMessageHandler::SystemLogsGetter::RequestSystemLog(
772 const base::ListValue* args) {
773 if (!logs_requested_) {
774 DCHECK(!logs_received_);
777 SystemLogRequest log_request;
778 args->GetString(0, &log_request.log_key);
779 args->GetString(1, &log_request.cell_id);
781 if (logs_received_) {
782 SendLogs(log_request);
784 requests_.push_back(log_request);
788 void NetInternalsMessageHandler::SystemLogsGetter::LoadSystemLogs() {
789 if (logs_requested_ || !syslogs_provider_)
791 logs_requested_ = true;
792 syslogs_task_id_ = syslogs_provider_->RequestSyslogs(
793 false, // compress logs.
794 chromeos::system::SyslogsProvider::SYSLOGS_NETWORK,
796 &NetInternalsMessageHandler::SystemLogsGetter::OnSystemLogsLoaded,
797 base::Unretained(this)),
801 void NetInternalsMessageHandler::SystemLogsGetter::OnSystemLogsLoaded(
802 chromeos::system::LogDictionaryType* sys_info,
803 std::string* ignored_content) {
804 DCHECK(!ignored_content);
805 logs_.reset(sys_info);
806 logs_received_ = true;
807 for (std::list<SystemLogRequest>::iterator request_it = requests_.begin();
808 request_it != requests_.end();
810 SendLogs(*request_it);
815 void NetInternalsMessageHandler::SystemLogsGetter::SendLogs(
816 const SystemLogRequest& request) {
817 base::DictionaryValue* result = new base::DictionaryValue();
818 chromeos::system::LogDictionaryType::iterator log_it =
819 logs_->find(request.log_key);
820 if (log_it != logs_->end()) {
821 if (!log_it->second.empty()) {
822 result->SetString("log", log_it->second);
824 result->SetString("log", "<no relevant lines found>");
827 result->SetString("log", "<invalid log name>");
829 result->SetString("cellId", request.cell_id);
831 handler_->SendJavascriptCommand("getSystemLogCallback", result);
833 #endif // defined(OS_CHROMEOS)
835 ////////////////////////////////////////////////////////////////////////////////
837 // NetInternalsMessageHandler::IOThreadImpl
839 ////////////////////////////////////////////////////////////////////////////////
841 NetInternalsMessageHandler::IOThreadImpl::IOThreadImpl(
842 const base::WeakPtr<NetInternalsMessageHandler>& handler,
844 net::URLRequestContextGetter* main_context_getter)
846 io_thread_(io_thread),
847 main_context_getter_(main_context_getter),
848 was_webui_deleted_(false) {
849 DCHECK_CURRENTLY_ON(BrowserThread::UI);
850 AddRequestContextGetter(main_context_getter);
853 NetInternalsMessageHandler::IOThreadImpl::~IOThreadImpl() {
854 DCHECK_CURRENTLY_ON(BrowserThread::UI);
857 void NetInternalsMessageHandler::IOThreadImpl::AddRequestContextGetter(
858 net::URLRequestContextGetter* context_getter) {
859 DCHECK_CURRENTLY_ON(BrowserThread::UI);
860 context_getters_.push_back(context_getter);
863 void NetInternalsMessageHandler::IOThreadImpl::CallbackHelper(
864 MessageHandler method,
865 scoped_refptr<IOThreadImpl> io_thread,
866 const base::ListValue* list) {
867 DCHECK_CURRENTLY_ON(BrowserThread::UI);
869 // We need to make a copy of the value in order to pass it over to the IO
870 // thread. |list_copy| will be deleted when the task is destroyed. The called
871 // |method| cannot take ownership of |list_copy|.
872 base::ListValue* list_copy =
873 (list && list->GetSize()) ? list->DeepCopy() : NULL;
875 BrowserThread::PostTask(
876 BrowserThread::IO, FROM_HERE,
877 base::Bind(method, io_thread, base::Owned(list_copy)));
880 void NetInternalsMessageHandler::IOThreadImpl::Detach() {
881 DCHECK_CURRENTLY_ON(BrowserThread::IO);
882 // Unregister with network stack to observe events.
884 net_log()->RemoveThreadSafeObserver(this);
886 // Cancel any in-progress connection tests.
887 connection_tester_.reset();
890 void NetInternalsMessageHandler::IOThreadImpl::OnWebUIDeleted() {
891 DCHECK_CURRENTLY_ON(BrowserThread::UI);
892 was_webui_deleted_ = true;
895 void NetInternalsMessageHandler::IOThreadImpl::OnRendererReady(
896 const base::ListValue* list) {
897 DCHECK_CURRENTLY_ON(BrowserThread::IO);
899 // If we have any pending entries, go ahead and get rid of them, so they won't
900 // appear before the REQUEST_ALIVE events we add for currently active
902 PostPendingEntries();
904 SendJavascriptCommand("receivedConstants", NetInternalsUI::GetConstants());
906 // Add entries for ongoing URL requests.
907 PrePopulateEventList();
910 // Register with network stack to observe events.
911 io_thread_->net_log()->AddThreadSafeObserver(this,
912 net::NetLog::LOG_ALL_BUT_BYTES);
916 void NetInternalsMessageHandler::IOThreadImpl::OnGetProxySettings(
917 const base::ListValue* list) {
919 net::ProxyService* proxy_service = GetMainContext()->proxy_service();
921 base::DictionaryValue* dict = new base::DictionaryValue();
922 if (proxy_service->fetched_config().is_valid())
923 dict->Set("original", proxy_service->fetched_config().ToValue());
924 if (proxy_service->config().is_valid())
925 dict->Set("effective", proxy_service->config().ToValue());
927 SendJavascriptCommand("receivedProxySettings", dict);
930 void NetInternalsMessageHandler::IOThreadImpl::OnReloadProxySettings(
931 const base::ListValue* list) {
933 GetMainContext()->proxy_service()->ForceReloadProxyConfig();
935 // Cause the renderer to be notified of the new values.
936 OnGetProxySettings(NULL);
939 void NetInternalsMessageHandler::IOThreadImpl::OnGetBadProxies(
940 const base::ListValue* list) {
943 const net::ProxyRetryInfoMap& bad_proxies_map =
944 GetMainContext()->proxy_service()->proxy_retry_info();
946 base::ListValue* dict_list = new base::ListValue();
948 for (net::ProxyRetryInfoMap::const_iterator it = bad_proxies_map.begin();
949 it != bad_proxies_map.end(); ++it) {
950 const std::string& proxy_uri = it->first;
951 const net::ProxyRetryInfo& retry_info = it->second;
953 base::DictionaryValue* dict = new base::DictionaryValue();
954 dict->SetString("proxy_uri", proxy_uri);
955 dict->SetString("bad_until",
956 net::NetLog::TickCountToString(retry_info.bad_until));
958 dict_list->Append(dict);
961 SendJavascriptCommand("receivedBadProxies", dict_list);
964 void NetInternalsMessageHandler::IOThreadImpl::OnClearBadProxies(
965 const base::ListValue* list) {
967 GetMainContext()->proxy_service()->ClearBadProxiesCache();
969 // Cause the renderer to be notified of the new values.
970 OnGetBadProxies(NULL);
973 void NetInternalsMessageHandler::IOThreadImpl::OnGetHostResolverInfo(
974 const base::ListValue* list) {
976 net::URLRequestContext* context = GetMainContext();
977 net::HostCache* cache = GetHostResolverCache(context);
980 SendJavascriptCommand("receivedHostResolverInfo", NULL);
984 base::DictionaryValue* dict = new base::DictionaryValue();
986 base::Value* dns_config = context->host_resolver()->GetDnsConfigAsValue();
988 dict->Set("dns_config", dns_config);
991 "default_address_family",
992 static_cast<int>(context->host_resolver()->GetDefaultAddressFamily()));
994 base::DictionaryValue* cache_info_dict = new base::DictionaryValue();
996 cache_info_dict->SetInteger(
998 static_cast<int>(cache->max_entries()));
1000 base::ListValue* entry_list = new base::ListValue();
1002 net::HostCache::EntryMap::Iterator it(cache->entries());
1003 for (; it.HasNext(); it.Advance()) {
1004 const net::HostCache::Key& key = it.key();
1005 const net::HostCache::Entry& entry = it.value();
1007 base::DictionaryValue* entry_dict = new base::DictionaryValue();
1009 entry_dict->SetString("hostname", key.hostname);
1010 entry_dict->SetInteger("address_family",
1011 static_cast<int>(key.address_family));
1012 entry_dict->SetString("expiration",
1013 net::NetLog::TickCountToString(it.expiration()));
1015 if (entry.error != net::OK) {
1016 entry_dict->SetInteger("error", entry.error);
1018 // Append all of the resolved addresses.
1019 base::ListValue* address_list = new base::ListValue();
1020 for (size_t i = 0; i < entry.addrlist.size(); ++i) {
1021 address_list->AppendString(entry.addrlist[i].ToStringWithoutPort());
1023 entry_dict->Set("addresses", address_list);
1026 entry_list->Append(entry_dict);
1029 cache_info_dict->Set("entries", entry_list);
1030 dict->Set("cache", cache_info_dict);
1032 SendJavascriptCommand("receivedHostResolverInfo", dict);
1035 void NetInternalsMessageHandler::IOThreadImpl::OnClearHostResolverCache(
1036 const base::ListValue* list) {
1038 net::HostCache* cache = GetHostResolverCache(GetMainContext());
1043 // Cause the renderer to be notified of the new values.
1044 OnGetHostResolverInfo(NULL);
1047 void NetInternalsMessageHandler::IOThreadImpl::OnEnableIPv6(
1048 const base::ListValue* list) {
1050 net::HostResolver* host_resolver = GetMainContext()->host_resolver();
1052 host_resolver->SetDefaultAddressFamily(net::ADDRESS_FAMILY_UNSPECIFIED);
1054 // Cause the renderer to be notified of the new value.
1055 OnGetHostResolverInfo(NULL);
1058 void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTests(
1059 const base::ListValue* list) {
1060 // |value| should be: [<URL to test>].
1061 base::string16 url_str;
1062 CHECK(list->GetString(0, &url_str));
1064 // Try to fix-up the user provided URL into something valid.
1065 // For example, turn "www.google.com" into "http://www.google.com".
1066 GURL url(url_fixer::FixupURL(base::UTF16ToUTF8(url_str), std::string()));
1068 connection_tester_.reset(new ConnectionTester(
1070 io_thread_->globals()->proxy_script_fetcher_context.get(),
1072 connection_tester_->RunAllTests(url);
1075 void NetInternalsMessageHandler::IOThreadImpl::OnHSTSQuery(
1076 const base::ListValue* list) {
1077 // |list| should be: [<domain to query>].
1079 CHECK(list->GetString(0, &domain));
1080 base::DictionaryValue* result = new base::DictionaryValue();
1082 if (!base::IsStringASCII(domain)) {
1083 result->SetString("error", "non-ASCII domain name");
1085 net::TransportSecurityState* transport_security_state =
1086 GetMainContext()->transport_security_state();
1087 if (!transport_security_state) {
1088 result->SetString("error", "no TransportSecurityState active");
1090 net::TransportSecurityState::DomainState static_state;
1091 const bool found_static = transport_security_state->GetStaticDomainState(
1092 domain, true, &static_state);
1094 result->SetBoolean("has_static_sts",
1095 found_static && static_state.ShouldUpgradeToSSL());
1096 result->SetInteger("static_upgrade_mode",
1097 static_cast<int>(static_state.sts.upgrade_mode));
1098 result->SetBoolean("static_sts_include_subdomains",
1099 static_state.sts.include_subdomains);
1100 result->SetDouble("static_sts_observed",
1101 static_state.sts.last_observed.ToDoubleT());
1102 result->SetDouble("static_sts_expiry",
1103 static_state.sts.expiry.ToDoubleT());
1104 result->SetBoolean("has_static_pkp",
1105 found_static && static_state.HasPublicKeyPins());
1106 result->SetBoolean("static_pkp_include_subdomains",
1107 static_state.pkp.include_subdomains);
1108 result->SetDouble("static_pkp_observed",
1109 static_state.pkp.last_observed.ToDoubleT());
1110 result->SetDouble("static_pkp_expiry",
1111 static_state.pkp.expiry.ToDoubleT());
1112 result->SetString("static_spki_hashes",
1113 HashesToBase64String(static_state.pkp.spki_hashes));
1116 net::TransportSecurityState::DomainState dynamic_state;
1117 const bool found_dynamic =
1118 transport_security_state->GetDynamicDomainState(domain,
1120 if (found_dynamic) {
1121 result->SetInteger("dynamic_upgrade_mode",
1122 static_cast<int>(dynamic_state.sts.upgrade_mode));
1123 result->SetBoolean("dynamic_sts_include_subdomains",
1124 dynamic_state.sts.include_subdomains);
1125 result->SetBoolean("dynamic_pkp_include_subdomains",
1126 dynamic_state.pkp.include_subdomains);
1127 result->SetDouble("dynamic_sts_observed",
1128 dynamic_state.sts.last_observed.ToDoubleT());
1129 result->SetDouble("dynamic_pkp_observed",
1130 dynamic_state.pkp.last_observed.ToDoubleT());
1131 result->SetDouble("dynamic_sts_expiry",
1132 dynamic_state.sts.expiry.ToDoubleT());
1133 result->SetDouble("dynamic_pkp_expiry",
1134 dynamic_state.pkp.expiry.ToDoubleT());
1135 result->SetString("dynamic_spki_hashes",
1136 HashesToBase64String(dynamic_state.pkp.spki_hashes));
1139 result->SetBoolean("result", found_static || found_dynamic);
1141 result->SetString("domain", static_state.domain);
1142 } else if (found_dynamic) {
1143 result->SetString("domain", dynamic_state.domain);
1145 result->SetString("domain", domain);
1150 SendJavascriptCommand("receivedHSTSResult", result);
1153 void NetInternalsMessageHandler::IOThreadImpl::OnHSTSAdd(
1154 const base::ListValue* list) {
1155 // |list| should be: [<domain to query>, <STS include subdomains>, <PKP
1156 // include subdomains>, <key pins>].
1158 CHECK(list->GetString(0, &domain));
1159 if (!base::IsStringASCII(domain)) {
1160 // Silently fail. The user will get a helpful error if they query for the
1164 bool sts_include_subdomains;
1165 CHECK(list->GetBoolean(1, &sts_include_subdomains));
1166 bool pkp_include_subdomains;
1167 CHECK(list->GetBoolean(2, &pkp_include_subdomains));
1168 std::string hashes_str;
1169 CHECK(list->GetString(3, &hashes_str));
1171 net::TransportSecurityState* transport_security_state =
1172 GetMainContext()->transport_security_state();
1173 if (!transport_security_state)
1176 base::Time expiry = base::Time::Now() + base::TimeDelta::FromDays(1000);
1177 net::HashValueVector hashes;
1178 if (!hashes_str.empty()) {
1179 if (!Base64StringToHashes(hashes_str, &hashes))
1183 transport_security_state->AddHSTS(domain, expiry, sts_include_subdomains);
1184 transport_security_state->AddHPKP(domain, expiry, pkp_include_subdomains,
1188 void NetInternalsMessageHandler::IOThreadImpl::OnHSTSDelete(
1189 const base::ListValue* list) {
1190 // |list| should be: [<domain to query>].
1192 CHECK(list->GetString(0, &domain));
1193 if (!base::IsStringASCII(domain)) {
1194 // There cannot be a unicode entry in the HSTS set.
1197 net::TransportSecurityState* transport_security_state =
1198 GetMainContext()->transport_security_state();
1199 if (!transport_security_state)
1202 transport_security_state->DeleteDynamicDataForHost(domain);
1205 void NetInternalsMessageHandler::IOThreadImpl::OnGetHttpCacheInfo(
1206 const base::ListValue* list) {
1208 base::DictionaryValue* info_dict = new base::DictionaryValue();
1209 base::DictionaryValue* stats_dict = new base::DictionaryValue();
1211 disk_cache::Backend* disk_cache = GetDiskCacheBackend(GetMainContext());
1214 // Extract the statistics key/value pairs from the backend.
1215 std::vector<std::pair<std::string, std::string> > stats;
1216 disk_cache->GetStats(&stats);
1217 for (size_t i = 0; i < stats.size(); ++i) {
1218 stats_dict->SetStringWithoutPathExpansion(
1219 stats[i].first, stats[i].second);
1223 info_dict->Set("stats", stats_dict);
1225 SendJavascriptCommand("receivedHttpCacheInfo", info_dict);
1228 void NetInternalsMessageHandler::IOThreadImpl::OnGetSocketPoolInfo(
1229 const base::ListValue* list) {
1231 net::HttpNetworkSession* http_network_session =
1232 GetHttpNetworkSession(GetMainContext());
1234 base::Value* socket_pool_info = NULL;
1235 if (http_network_session)
1236 socket_pool_info = http_network_session->SocketPoolInfoToValue();
1238 SendJavascriptCommand("receivedSocketPoolInfo", socket_pool_info);
1241 void NetInternalsMessageHandler::IOThreadImpl::OnGetSessionNetworkStats(
1242 const base::ListValue* list) {
1244 net::HttpNetworkSession* http_network_session =
1245 GetHttpNetworkSession(main_context_getter_->GetURLRequestContext());
1247 base::Value* network_info = NULL;
1248 if (http_network_session) {
1249 ChromeNetworkDelegate* net_delegate =
1250 static_cast<ChromeNetworkDelegate*>(
1251 http_network_session->network_delegate());
1253 network_info = net_delegate->SessionNetworkStatsInfoToValue();
1256 SendJavascriptCommand("receivedSessionNetworkStats", network_info);
1259 void NetInternalsMessageHandler::IOThreadImpl::OnFlushSocketPools(
1260 const base::ListValue* list) {
1262 net::HttpNetworkSession* http_network_session =
1263 GetHttpNetworkSession(GetMainContext());
1265 if (http_network_session)
1266 http_network_session->CloseAllConnections();
1269 void NetInternalsMessageHandler::IOThreadImpl::OnCloseIdleSockets(
1270 const base::ListValue* list) {
1272 net::HttpNetworkSession* http_network_session =
1273 GetHttpNetworkSession(GetMainContext());
1275 if (http_network_session)
1276 http_network_session->CloseIdleConnections();
1279 void NetInternalsMessageHandler::IOThreadImpl::OnGetSpdySessionInfo(
1280 const base::ListValue* list) {
1282 net::HttpNetworkSession* http_network_session =
1283 GetHttpNetworkSession(GetMainContext());
1285 base::Value* spdy_info = http_network_session ?
1286 http_network_session->SpdySessionPoolInfoToValue() : NULL;
1287 SendJavascriptCommand("receivedSpdySessionInfo", spdy_info);
1290 void NetInternalsMessageHandler::IOThreadImpl::OnGetSpdyStatus(
1291 const base::ListValue* list) {
1293 base::DictionaryValue* status_dict = new base::DictionaryValue();
1295 net::HttpNetworkSession* http_network_session =
1296 GetHttpNetworkSession(GetMainContext());
1298 status_dict->SetBoolean("spdy_enabled",
1299 net::HttpStreamFactory::spdy_enabled());
1300 status_dict->SetBoolean(
1301 "use_alternate_protocols",
1302 http_network_session->params().use_alternate_protocols);
1303 status_dict->SetBoolean("force_spdy_over_ssl",
1304 http_network_session->params().force_spdy_over_ssl);
1305 status_dict->SetBoolean("force_spdy_always",
1306 http_network_session->params().force_spdy_always);
1308 std::vector<std::string> next_protos;
1309 http_network_session->GetNextProtos(&next_protos);
1310 std::string next_protos_string = JoinString(next_protos, ',');
1311 status_dict->SetString("next_protos", next_protos_string);
1313 SendJavascriptCommand("receivedSpdyStatus", status_dict);
1317 NetInternalsMessageHandler::IOThreadImpl::OnGetSpdyAlternateProtocolMappings(
1318 const base::ListValue* list) {
1320 base::ListValue* dict_list = new base::ListValue();
1322 const net::HttpServerProperties& http_server_properties =
1323 *GetMainContext()->http_server_properties();
1325 const net::AlternateProtocolMap& map =
1326 http_server_properties.alternate_protocol_map();
1328 for (net::AlternateProtocolMap::const_iterator it = map.begin();
1329 it != map.end(); ++it) {
1330 base::DictionaryValue* dict = new base::DictionaryValue();
1331 dict->SetString("host_port_pair", it->first.ToString());
1332 dict->SetString("alternate_protocol", it->second.ToString());
1333 dict_list->Append(dict);
1336 SendJavascriptCommand("receivedSpdyAlternateProtocolMappings", dict_list);
1339 void NetInternalsMessageHandler::IOThreadImpl::OnGetQuicInfo(
1340 const base::ListValue* list) {
1342 net::HttpNetworkSession* http_network_session =
1343 GetHttpNetworkSession(GetMainContext());
1345 base::Value* quic_info = http_network_session ?
1346 http_network_session->QuicInfoToValue() : NULL;
1347 SendJavascriptCommand("receivedQuicInfo", quic_info);
1351 void NetInternalsMessageHandler::IOThreadImpl::OnGetServiceProviders(
1352 const base::ListValue* list) {
1355 base::DictionaryValue* service_providers = new base::DictionaryValue();
1357 WinsockLayeredServiceProviderList layered_providers;
1358 GetWinsockLayeredServiceProviders(&layered_providers);
1359 base::ListValue* layered_provider_list = new base::ListValue();
1360 for (size_t i = 0; i < layered_providers.size(); ++i) {
1361 base::DictionaryValue* service_dict = new base::DictionaryValue();
1362 service_dict->SetString("name", layered_providers[i].name);
1363 service_dict->SetInteger("version", layered_providers[i].version);
1364 service_dict->SetInteger("chain_length", layered_providers[i].chain_length);
1365 service_dict->SetInteger("socket_type", layered_providers[i].socket_type);
1366 service_dict->SetInteger("socket_protocol",
1367 layered_providers[i].socket_protocol);
1368 service_dict->SetString("path", layered_providers[i].path);
1370 layered_provider_list->Append(service_dict);
1372 service_providers->Set("service_providers", layered_provider_list);
1374 WinsockNamespaceProviderList namespace_providers;
1375 GetWinsockNamespaceProviders(&namespace_providers);
1376 base::ListValue* namespace_list = new base::ListValue;
1377 for (size_t i = 0; i < namespace_providers.size(); ++i) {
1378 base::DictionaryValue* namespace_dict = new base::DictionaryValue();
1379 namespace_dict->SetString("name", namespace_providers[i].name);
1380 namespace_dict->SetBoolean("active", namespace_providers[i].active);
1381 namespace_dict->SetInteger("version", namespace_providers[i].version);
1382 namespace_dict->SetInteger("type", namespace_providers[i].type);
1384 namespace_list->Append(namespace_dict);
1386 service_providers->Set("namespace_providers", namespace_list);
1388 SendJavascriptCommand("receivedServiceProviders", service_providers);
1392 #if defined(OS_CHROMEOS)
1393 void NetInternalsMessageHandler::OnRefreshSystemLogs(
1394 const base::ListValue* list) {
1396 DCHECK(syslogs_getter_.get());
1397 syslogs_getter_->DeleteSystemLogs();
1398 syslogs_getter_->LoadSystemLogs();
1401 void NetInternalsMessageHandler::OnGetSystemLog(
1402 const base::ListValue* list) {
1403 DCHECK(syslogs_getter_.get());
1404 syslogs_getter_->RequestSystemLog(list);
1407 void NetInternalsMessageHandler::ImportONCFileToNSSDB(
1408 const std::string& onc_blob,
1409 const std::string& passcode,
1410 net::NSSCertDatabase* nssdb) {
1412 user_manager::User* user = chromeos::ProfileHelper::Get()->GetUserByProfile(
1413 Profile::FromWebUI(web_ui()));
1416 onc::ONCSource onc_source = onc::ONC_SOURCE_USER_IMPORT;
1418 base::ListValue network_configs;
1419 base::DictionaryValue global_network_config;
1420 base::ListValue certificates;
1421 if (!chromeos::onc::ParseAndValidateOncForImport(onc_blob,
1425 &global_network_config,
1427 error = "Errors occurred during the ONC parsing. ";
1430 chromeos::onc::CertificateImporterImpl cert_importer(nssdb);
1431 if (!cert_importer.ImportCertificates(certificates, onc_source, NULL))
1432 error += "Some certificates couldn't be imported. ";
1434 std::string network_error;
1435 chromeos::onc::ImportNetworksForUser(user, network_configs, &network_error);
1436 if (!network_error.empty())
1437 error += network_error;
1439 error = "User not found.";
1442 LOG_IF(ERROR, !error.empty()) << error;
1443 SendJavascriptCommand("receivedONCFileParse", new base::StringValue(error));
1446 void NetInternalsMessageHandler::OnImportONCFile(
1447 const base::ListValue* list) {
1448 std::string onc_blob;
1449 std::string passcode;
1450 if (list->GetSize() != 2 ||
1451 !list->GetString(0, &onc_blob) ||
1452 !list->GetString(1, &passcode)) {
1456 GetNSSCertDatabaseForProfile(
1457 Profile::FromWebUI(web_ui()),
1458 base::Bind(&NetInternalsMessageHandler::ImportONCFileToNSSDB, AsWeakPtr(),
1459 onc_blob, passcode));
1462 void NetInternalsMessageHandler::OnStoreDebugLogs(const base::ListValue* list) {
1465 SendJavascriptCommand("receivedStoreDebugLogs",
1466 new base::StringValue("Creating log file..."));
1467 Profile* profile = Profile::FromWebUI(web_ui());
1468 const DownloadPrefs* const prefs = DownloadPrefs::FromBrowserContext(profile);
1469 base::FilePath path = prefs->DownloadPath();
1470 if (file_manager::util::IsUnderNonNativeLocalPath(profile, path))
1471 path = prefs->GetDefaultDownloadDirectoryForProfile();
1472 chromeos::DebugLogWriter::StoreLogs(
1474 true, // should_compress
1475 base::Bind(&NetInternalsMessageHandler::OnStoreDebugLogsCompleted,
1479 void NetInternalsMessageHandler::OnStoreDebugLogsCompleted(
1480 const base::FilePath& log_path, bool succeeded) {
1483 status = "Created log file: " + log_path.BaseName().AsUTF8Unsafe();
1485 status = "Failed to create log file";
1486 SendJavascriptCommand("receivedStoreDebugLogs",
1487 new base::StringValue(status));
1490 void NetInternalsMessageHandler::OnSetNetworkDebugMode(
1491 const base::ListValue* list) {
1492 std::string subsystem;
1493 if (list->GetSize() != 1 || !list->GetString(0, &subsystem))
1495 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->
1499 &NetInternalsMessageHandler::OnSetNetworkDebugModeCompleted,
1504 void NetInternalsMessageHandler::OnSetNetworkDebugModeCompleted(
1505 const std::string& subsystem,
1509 status = "Debug mode is changed to " + subsystem;
1511 status = "Failed to change debug mode to " + subsystem;
1512 SendJavascriptCommand("receivedSetNetworkDebugMode",
1513 new base::StringValue(status));
1515 #endif // defined(OS_CHROMEOS)
1517 void NetInternalsMessageHandler::IOThreadImpl::OnSetLogLevel(
1518 const base::ListValue* list) {
1520 std::string log_level_string;
1521 if (!list->GetString(0, &log_level_string) ||
1522 !base::StringToInt(log_level_string, &log_level)) {
1527 DCHECK_GE(log_level, net::NetLog::LOG_ALL);
1528 DCHECK_LT(log_level, net::NetLog::LOG_NONE);
1529 net_log()->SetObserverLogLevel(
1530 this, static_cast<net::NetLog::LogLevel>(log_level));
1533 // Note that unlike other methods of IOThreadImpl, this function
1534 // can be called from ANY THREAD.
1535 void NetInternalsMessageHandler::IOThreadImpl::OnAddEntry(
1536 const net::NetLog::Entry& entry) {
1537 BrowserThread::PostTask(
1538 BrowserThread::IO, FROM_HERE,
1539 base::Bind(&IOThreadImpl::AddEntryToQueue, this, entry.ToValue()));
1542 void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTestSuite() {
1543 SendJavascriptCommand("receivedStartConnectionTestSuite", NULL);
1546 void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTestExperiment(
1547 const ConnectionTester::Experiment& experiment) {
1548 SendJavascriptCommand(
1549 "receivedStartConnectionTestExperiment",
1550 ExperimentToValue(experiment));
1554 NetInternalsMessageHandler::IOThreadImpl::OnCompletedConnectionTestExperiment(
1555 const ConnectionTester::Experiment& experiment,
1557 base::DictionaryValue* dict = new base::DictionaryValue();
1559 dict->Set("experiment", ExperimentToValue(experiment));
1560 dict->SetInteger("result", result);
1562 SendJavascriptCommand(
1563 "receivedCompletedConnectionTestExperiment",
1568 NetInternalsMessageHandler::IOThreadImpl::OnCompletedConnectionTestSuite() {
1569 SendJavascriptCommand(
1570 "receivedCompletedConnectionTestSuite",
1574 // Note that this can be called from ANY THREAD.
1575 void NetInternalsMessageHandler::IOThreadImpl::SendJavascriptCommand(
1576 const std::string& command,
1578 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
1579 if (handler_.get() && !was_webui_deleted_) {
1580 // We check |handler_| in case it was deleted on the UI thread earlier
1581 // while we were running on the IO thread.
1582 handler_->SendJavascriptCommand(command, arg);
1589 if (!BrowserThread::PostTask(
1590 BrowserThread::UI, FROM_HERE,
1591 base::Bind(&IOThreadImpl::SendJavascriptCommand, this, command, arg))) {
1592 // Failed posting the task, avoid leaking.
1597 void NetInternalsMessageHandler::IOThreadImpl::AddEntryToQueue(
1598 base::Value* entry) {
1599 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1600 if (!pending_entries_.get()) {
1601 pending_entries_.reset(new base::ListValue());
1602 BrowserThread::PostDelayedTask(
1603 BrowserThread::IO, FROM_HERE,
1604 base::Bind(&IOThreadImpl::PostPendingEntries, this),
1605 base::TimeDelta::FromMilliseconds(kNetLogEventDelayMilliseconds));
1607 pending_entries_->Append(entry);
1610 void NetInternalsMessageHandler::IOThreadImpl::PostPendingEntries() {
1611 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1612 if (pending_entries_.get())
1613 SendJavascriptCommand("receivedLogEntries", pending_entries_.release());
1616 void NetInternalsMessageHandler::IOThreadImpl::PrePopulateEventList() {
1617 // Use a set to prevent duplicates.
1618 std::set<net::URLRequestContext*> contexts;
1619 for (ContextGetterList::const_iterator getter = context_getters_.begin();
1620 getter != context_getters_.end(); ++getter) {
1621 contexts.insert((*getter)->GetURLRequestContext());
1623 contexts.insert(io_thread_->globals()->proxy_script_fetcher_context.get());
1624 contexts.insert(io_thread_->globals()->system_request_context.get());
1626 // Put together the list of all requests.
1627 std::vector<const net::URLRequest*> requests;
1628 for (std::set<net::URLRequestContext*>::const_iterator context =
1630 context != contexts.end(); ++context) {
1631 std::set<const net::URLRequest*>* context_requests =
1632 (*context)->url_requests();
1633 for (std::set<const net::URLRequest*>::const_iterator request_it =
1634 context_requests->begin();
1635 request_it != context_requests->end(); ++request_it) {
1636 DCHECK_EQ(io_thread_->net_log(), (*request_it)->net_log().net_log());
1637 requests.push_back(*request_it);
1641 // Sort by creation time.
1642 std::sort(requests.begin(), requests.end(), RequestCreatedBefore);
1644 // Create fake events.
1645 for (std::vector<const net::URLRequest*>::const_iterator request_it =
1647 request_it != requests.end(); ++request_it) {
1648 const net::URLRequest* request = *request_it;
1649 net::NetLog::ParametersCallback callback =
1650 base::Bind(&GetRequestStateAsValue, base::Unretained(request));
1652 // Create and add the entry directly, to avoid sending it to any other
1653 // NetLog observers.
1654 net::NetLog::EntryData entry_data(net::NetLog::TYPE_REQUEST_ALIVE,
1655 request->net_log().source(),
1656 net::NetLog::PHASE_BEGIN,
1657 request->creation_time(),
1659 net::NetLog::Entry entry(&entry_data, request->net_log().GetLogLevel());
1661 // Have to add |entry| to the queue synchronously, as there may already
1662 // be posted tasks queued up to add other events for |request|, which we
1663 // want |entry| to precede.
1664 AddEntryToQueue(entry.ToValue());
1671 ////////////////////////////////////////////////////////////////////////////////
1675 ////////////////////////////////////////////////////////////////////////////////
1678 base::Value* NetInternalsUI::GetConstants() {
1679 base::DictionaryValue* constants_dict = net::NetLogLogger::GetConstants();
1680 DCHECK(constants_dict);
1682 // Add a dictionary with the version of the client and its command line
1685 base::DictionaryValue* dict = new base::DictionaryValue();
1687 chrome::VersionInfo version_info;
1689 if (!version_info.is_valid()) {
1690 DLOG(ERROR) << "Unable to create chrome::VersionInfo";
1692 // We have everything we need to send the right values.
1693 dict->SetString("name", version_info.Name());
1694 dict->SetString("version", version_info.Version());
1695 dict->SetString("cl", version_info.LastChange());
1696 dict->SetString("version_mod",
1697 chrome::VersionInfo::GetVersionStringModifier());
1698 dict->SetString("official",
1699 version_info.IsOfficialBuild() ? "official" :
1701 dict->SetString("os_type", version_info.OSType());
1702 dict->SetString("command_line",
1703 CommandLine::ForCurrentProcess()->GetCommandLineString());
1706 constants_dict->Set("clientInfo", dict);
1709 return constants_dict;
1712 NetInternalsUI::NetInternalsUI(content::WebUI* web_ui)
1713 : WebUIController(web_ui) {
1714 web_ui->AddMessageHandler(new NetInternalsMessageHandler());
1716 // Set up the chrome://net-internals/ source.
1717 Profile* profile = Profile::FromWebUI(web_ui);
1718 content::WebUIDataSource::Add(profile, CreateNetInternalsHTMLSource());