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/extensions/extension_service.h"
37 #include "chrome/browser/io_thread.h"
38 #include "chrome/browser/net/chrome_net_log.h"
39 #include "chrome/browser/net/chrome_network_delegate.h"
40 #include "chrome/browser/net/connection_tester.h"
41 #include "chrome/browser/prerender/prerender_manager.h"
42 #include "chrome/browser/prerender/prerender_manager_factory.h"
43 #include "chrome/browser/profiles/profile.h"
44 #include "chrome/browser/ui/webui/extensions/extension_basic_info.h"
45 #include "chrome/common/chrome_paths.h"
46 #include "chrome/common/chrome_version_info.h"
47 #include "chrome/common/logging_chrome.h"
48 #include "chrome/common/pref_names.h"
49 #include "chrome/common/url_constants.h"
50 #include "components/onc/onc_constants.h"
51 #include "components/url_fixer/url_fixer.h"
52 #include "content/public/browser/browser_thread.h"
53 #include "content/public/browser/notification_details.h"
54 #include "content/public/browser/resource_dispatcher_host.h"
55 #include "content/public/browser/web_contents.h"
56 #include "content/public/browser/web_ui.h"
57 #include "content/public/browser/web_ui_data_source.h"
58 #include "content/public/browser/web_ui_message_handler.h"
59 #include "extensions/browser/extension_registry.h"
60 #include "extensions/browser/extension_system.h"
61 #include "extensions/common/extension_set.h"
62 #include "grit/generated_resources.h"
63 #include "grit/net_internals_resources.h"
64 #include "net/base/net_errors.h"
65 #include "net/base/net_log_logger.h"
66 #include "net/base/net_util.h"
67 #include "net/disk_cache/disk_cache.h"
68 #include "net/dns/host_cache.h"
69 #include "net/dns/host_resolver.h"
70 #include "net/http/http_cache.h"
71 #include "net/http/http_network_layer.h"
72 #include "net/http/http_network_session.h"
73 #include "net/http/http_server_properties.h"
74 #include "net/http/http_stream_factory.h"
75 #include "net/http/transport_security_state.h"
76 #include "net/proxy/proxy_service.h"
77 #include "net/url_request/url_request_context.h"
78 #include "net/url_request/url_request_context_getter.h"
79 #include "ui/base/resource/resource_bundle.h"
81 #if defined(OS_CHROMEOS)
82 #include "chrome/browser/chromeos/login/users/user.h"
83 #include "chrome/browser/chromeos/login/users/user_manager.h"
84 #include "chrome/browser/chromeos/net/onc_utils.h"
85 #include "chrome/browser/chromeos/system/syslogs_provider.h"
86 #include "chrome/browser/net/nss_context.h"
87 #include "chromeos/dbus/dbus_thread_manager.h"
88 #include "chromeos/dbus/debug_daemon_client.h"
89 #include "chromeos/network/onc/onc_certificate_importer_impl.h"
90 #include "chromeos/network/onc/onc_utils.h"
93 #include "chrome/browser/net/service_providers_win.h"
96 using base::StringValue;
97 using content::BrowserThread;
98 using content::WebContents;
99 using content::WebUIMessageHandler;
103 // Delay between when an event occurs and when it is passed to the Javascript
104 // page. All events that occur during this period are grouped together and
105 // sent to the page at once, which reduces context switching and CPU usage.
106 const int kNetLogEventDelayMilliseconds = 100;
108 // Returns the HostCache for |context|'s primary HostResolver, or NULL if
110 net::HostCache* GetHostResolverCache(net::URLRequestContext* context) {
111 return context->host_resolver()->GetHostCache();
114 std::string HashesToBase64String(const net::HashValueVector& hashes) {
116 for (size_t i = 0; i != hashes.size(); ++i) {
119 str += hashes[i].ToString();
124 bool Base64StringToHashes(const std::string& hashes_str,
125 net::HashValueVector* hashes) {
127 std::vector<std::string> vector_hash_str;
128 base::SplitString(hashes_str, ',', &vector_hash_str);
130 for (size_t i = 0; i != vector_hash_str.size(); ++i) {
131 std::string hash_str;
132 base::RemoveChars(vector_hash_str[i], " \t\r\n", &hash_str);
134 // Skip past unrecognized hash algos
135 // But return false on malformatted input
136 if (hash_str.empty())
138 if (hash_str.compare(0, 5, "sha1/") != 0 &&
139 hash_str.compare(0, 7, "sha256/") != 0) {
142 if (!hash.FromString(hash_str))
144 hashes->push_back(hash);
149 // Returns a Value representing the state of a pre-existing URLRequest when
150 // net-internals was opened.
151 base::Value* GetRequestStateAsValue(const net::URLRequest* request,
152 net::NetLog::LogLevel log_level) {
153 return request->GetStateAsValue();
156 // Returns true if |request1| was created before |request2|.
157 bool RequestCreatedBefore(const net::URLRequest* request1,
158 const net::URLRequest* request2) {
159 return request1->creation_time() < request2->creation_time();
162 // Returns the disk cache backend for |context| if there is one, or NULL.
163 disk_cache::Backend* GetDiskCacheBackend(net::URLRequestContext* context) {
164 if (!context->http_transaction_factory())
167 net::HttpCache* http_cache = context->http_transaction_factory()->GetCache();
171 return http_cache->GetCurrentBackend();
174 // Returns the http network session for |context| if there is one.
175 // Otherwise, returns NULL.
176 net::HttpNetworkSession* GetHttpNetworkSession(
177 net::URLRequestContext* context) {
178 if (!context->http_transaction_factory())
181 return context->http_transaction_factory()->GetSession();
184 base::Value* ExperimentToValue(const ConnectionTester::Experiment& experiment) {
185 base::DictionaryValue* dict = new base::DictionaryValue();
187 if (experiment.url.is_valid())
188 dict->SetString("url", experiment.url.spec());
190 dict->SetString("proxy_settings_experiment",
191 ConnectionTester::ProxySettingsExperimentDescription(
192 experiment.proxy_settings_experiment));
193 dict->SetString("host_resolver_experiment",
194 ConnectionTester::HostResolverExperimentDescription(
195 experiment.host_resolver_experiment));
199 content::WebUIDataSource* CreateNetInternalsHTMLSource() {
200 content::WebUIDataSource* source =
201 content::WebUIDataSource::Create(chrome::kChromeUINetInternalsHost);
203 source->SetUseJsonJSFormatV2();
204 source->SetDefaultResource(IDR_NET_INTERNALS_INDEX_HTML);
205 source->AddResourcePath("index.js", IDR_NET_INTERNALS_INDEX_JS);
206 source->SetJsonPath("strings.js");
210 #if defined(OS_CHROMEOS)
211 // Following functions are used for getting debug logs. Logs are
212 // fetched from /var/log/* and put on the fileshelf.
214 // Called once StoreDebugLogs is complete. Takes two parameters:
215 // - log_path: where the log file was saved in the case of success;
216 // - succeeded: was the log file saved successfully.
217 typedef base::Callback<void(const base::FilePath& log_path,
218 bool succeded)> StoreDebugLogsCallback;
220 // Called upon completion of |WriteDebugLogToFile|. Closes file
221 // descriptor, deletes log file in the case of failure and calls
223 void WriteDebugLogToFileCompleted(const StoreDebugLogsCallback& callback,
224 const base::FilePath& file_path,
226 DCHECK_CURRENTLY_ON(BrowserThread::UI);
228 bool posted = BrowserThread::PostBlockingPoolTaskAndReply(
230 base::Bind(base::IgnoreResult(&base::DeleteFile), file_path, false),
231 base::Bind(callback, file_path, false));
235 callback.Run(file_path, true);
238 // Stores into |file_path| debug logs in the .tgz format. Calls
239 // |callback| upon completion.
240 void WriteDebugLogToFile(const StoreDebugLogsCallback& callback,
242 const base::FilePath& file_path) {
243 DCHECK_CURRENTLY_ON(BrowserThread::UI);
244 if (!file->IsValid()) {
246 "Can't create debug log file: " << file_path.AsUTF8Unsafe() << ", " <<
247 "error: " << file->error_details();
250 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->GetDebugLogs(
252 base::Bind(&WriteDebugLogToFileCompleted, callback, file_path));
255 // Stores debug logs in the .tgz archive on the |fileshelf|. The file
256 // is created on the worker pool, then writing to it is triggered from
257 // the UI thread, and finally it is closed (on success) or deleted (on
258 // failure) on the worker pool, prior to calling |callback|.
259 void StoreDebugLogs(const base::FilePath& fileshelf,
260 const StoreDebugLogsCallback& callback) {
261 DCHECK_CURRENTLY_ON(BrowserThread::UI);
262 DCHECK(!callback.is_null());
264 const base::FilePath::CharType kLogFileName[] =
265 FILE_PATH_LITERAL("debug-log.tgz");
267 base::FilePath file_path = fileshelf.Append(kLogFileName);
268 file_path = logging::GenerateTimestampedName(file_path, base::Time::Now());
270 int flags = base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE;
271 base::File* file = new base::File;
272 bool posted = BrowserThread::PostBlockingPoolTaskAndReply(
274 base::Bind(&base::File::Initialize,
275 base::Unretained(file), file_path, flags),
276 base::Bind(&WriteDebugLogToFile, callback, base::Owned(file), file_path));
279 #endif // defined(OS_CHROMEOS)
281 // This class receives javascript messages from the renderer.
282 // Note that the WebUI infrastructure runs on the UI thread, therefore all of
283 // this class's methods are expected to run on the UI thread.
285 // Since the network code we want to run lives on the IO thread, we proxy
286 // almost everything over to NetInternalsMessageHandler::IOThreadImpl, which
287 // runs on the IO thread.
289 // TODO(eroman): Can we start on the IO thread to begin with?
290 class NetInternalsMessageHandler
291 : public WebUIMessageHandler,
292 public base::SupportsWeakPtr<NetInternalsMessageHandler> {
294 NetInternalsMessageHandler();
295 virtual ~NetInternalsMessageHandler();
297 // WebUIMessageHandler implementation.
298 virtual void RegisterMessages() OVERRIDE;
300 // Calls g_browser.receive in the renderer, passing in |command| and |arg|.
301 // Takes ownership of |arg|. If the renderer is displaying a log file, the
302 // message will be ignored.
303 void SendJavascriptCommand(const std::string& command, base::Value* arg);
305 // Javascript message handlers.
306 void OnRendererReady(const base::ListValue* list);
307 void OnClearBrowserCache(const base::ListValue* list);
308 void OnGetPrerenderInfo(const base::ListValue* list);
309 void OnGetHistoricNetworkStats(const base::ListValue* list);
310 void OnGetExtensionInfo(const base::ListValue* list);
311 #if defined(OS_CHROMEOS)
312 void OnRefreshSystemLogs(const base::ListValue* list);
313 void OnGetSystemLog(const base::ListValue* list);
314 void OnImportONCFile(const base::ListValue* list);
315 void OnStoreDebugLogs(const base::ListValue* list);
316 void OnStoreDebugLogsCompleted(const base::FilePath& log_path,
318 void OnSetNetworkDebugMode(const base::ListValue* list);
319 void OnSetNetworkDebugModeCompleted(const std::string& subsystem,
322 // Callback to |GetNSSCertDatabaseForProfile| used to retrieve the database
323 // to which user's ONC defined certificates should be imported.
324 // It parses and imports |onc_blob|.
325 void ImportONCFileToNSSDB(const std::string& onc_blob,
326 const std::string& passcode,
327 net::NSSCertDatabase* nssdb);
333 #if defined(OS_CHROMEOS)
334 // Class that is used for getting network related ChromeOS logs.
335 // Logs are fetched from ChromeOS libcros on user request, and only when we
336 // don't yet have a copy of logs. If a copy is present, we send back data from
337 // it, else we save request and answer to it when we get logs from libcros.
338 // If needed, we also send request for system logs to libcros.
339 // Logs refresh has to be done explicitly, by deleting old logs and then
340 // loading them again.
341 class SystemLogsGetter {
343 SystemLogsGetter(NetInternalsMessageHandler* handler,
344 chromeos::system::SyslogsProvider* syslogs_provider);
347 // Deletes logs copy we currently have, and resets logs_requested and
348 // logs_received flags.
349 void DeleteSystemLogs();
350 // Starts log fetching. If logs copy is present, requested logs are sent
352 // If syslogs load request hasn't been sent to libcros yet, we do that now,
353 // and postpone sending response.
354 // Request data is specified by args:
355 // $1 : key of the log we are interested in.
356 // $2 : string used to identify request.
357 void RequestSystemLog(const base::ListValue* args);
358 // Requests logs from libcros, but only if we don't have a copy.
359 void LoadSystemLogs();
360 // Processes callback from libcros containing system logs. Postponed
361 // request responses are sent.
362 void OnSystemLogsLoaded(chromeos::system::LogDictionaryType* sys_info,
363 std::string* ignored_content);
366 // Struct we save postponed log request in.
367 struct SystemLogRequest {
372 // Processes request.
373 void SendLogs(const SystemLogRequest& request);
375 NetInternalsMessageHandler* handler_;
376 chromeos::system::SyslogsProvider* syslogs_provider_;
377 // List of postponed requests.
378 std::list<SystemLogRequest> requests_;
379 scoped_ptr<chromeos::system::LogDictionaryType> logs_;
381 bool logs_requested_;
382 base::CancelableTaskTracker tracker_;
383 // Libcros request task ID.
384 base::CancelableTaskTracker::TaskId syslogs_task_id_;
386 #endif // defined(OS_CHROMEOS)
388 // This is the "real" message handler, which lives on the IO thread.
389 scoped_refptr<IOThreadImpl> proxy_;
391 base::WeakPtr<prerender::PrerenderManager> prerender_manager_;
393 #if defined(OS_CHROMEOS)
394 // Class that handles getting and filtering system logs.
395 scoped_ptr<SystemLogsGetter> syslogs_getter_;
398 DISALLOW_COPY_AND_ASSIGN(NetInternalsMessageHandler);
401 // This class is the "real" message handler. It is allocated and destroyed on
402 // the UI thread. With the exception of OnAddEntry, OnWebUIDeleted, and
403 // SendJavascriptCommand, its methods are all expected to be called from the IO
404 // thread. OnAddEntry and SendJavascriptCommand can be called from any thread,
405 // and OnWebUIDeleted can only be called from the UI thread.
406 class NetInternalsMessageHandler::IOThreadImpl
407 : public base::RefCountedThreadSafe<
408 NetInternalsMessageHandler::IOThreadImpl,
409 BrowserThread::DeleteOnUIThread>,
410 public net::NetLog::ThreadSafeObserver,
411 public ConnectionTester::Delegate {
413 // Type for methods that can be used as MessageHandler callbacks.
414 typedef void (IOThreadImpl::*MessageHandler)(const base::ListValue*);
416 // Creates a proxy for |handler| that will live on the IO thread.
417 // |handler| is a weak pointer, since it is possible for the
418 // WebUIMessageHandler to be deleted on the UI thread while we were executing
419 // on the IO thread. |io_thread| is the global IOThread (it is passed in as
420 // an argument since we need to grab it from the UI thread).
422 const base::WeakPtr<NetInternalsMessageHandler>& handler,
424 net::URLRequestContextGetter* main_context_getter);
426 // Called on UI thread just after creation, to add a ContextGetter to
427 // |context_getters_|.
428 void AddRequestContextGetter(net::URLRequestContextGetter* context_getter);
430 // Helper method to enable a callback that will be executed on the IO thread.
431 static void CallbackHelper(MessageHandler method,
432 scoped_refptr<IOThreadImpl> io_thread,
433 const base::ListValue* list);
435 // Called once the WebUI has been deleted (i.e. renderer went away), on the
439 // Called when the WebUI is deleted. Prevents calling Javascript functions
440 // afterwards. Called on UI thread.
441 void OnWebUIDeleted();
443 //--------------------------------
444 // Javascript message handlers:
445 //--------------------------------
447 void OnRendererReady(const base::ListValue* list);
449 void OnGetProxySettings(const base::ListValue* list);
450 void OnReloadProxySettings(const base::ListValue* list);
451 void OnGetBadProxies(const base::ListValue* list);
452 void OnClearBadProxies(const base::ListValue* list);
453 void OnGetHostResolverInfo(const base::ListValue* list);
454 void OnClearHostResolverCache(const base::ListValue* list);
455 void OnEnableIPv6(const base::ListValue* list);
456 void OnStartConnectionTests(const base::ListValue* list);
457 void OnHSTSQuery(const base::ListValue* list);
458 void OnHSTSAdd(const base::ListValue* list);
459 void OnHSTSDelete(const base::ListValue* list);
460 void OnGetHttpCacheInfo(const base::ListValue* list);
461 void OnGetSocketPoolInfo(const base::ListValue* list);
462 void OnGetSessionNetworkStats(const base::ListValue* list);
463 void OnCloseIdleSockets(const base::ListValue* list);
464 void OnFlushSocketPools(const base::ListValue* list);
465 void OnGetSpdySessionInfo(const base::ListValue* list);
466 void OnGetSpdyStatus(const base::ListValue* list);
467 void OnGetSpdyAlternateProtocolMappings(const base::ListValue* list);
468 void OnGetQuicInfo(const base::ListValue* list);
470 void OnGetServiceProviders(const base::ListValue* list);
472 void OnSetLogLevel(const base::ListValue* list);
474 // ChromeNetLog::ThreadSafeObserver implementation:
475 virtual void OnAddEntry(const net::NetLog::Entry& entry) OVERRIDE;
477 // ConnectionTester::Delegate implementation:
478 virtual void OnStartConnectionTestSuite() OVERRIDE;
479 virtual void OnStartConnectionTestExperiment(
480 const ConnectionTester::Experiment& experiment) OVERRIDE;
481 virtual void OnCompletedConnectionTestExperiment(
482 const ConnectionTester::Experiment& experiment,
483 int result) OVERRIDE;
484 virtual void OnCompletedConnectionTestSuite() OVERRIDE;
486 // Helper that calls g_browser.receive in the renderer, passing in |command|
487 // and |arg|. Takes ownership of |arg|. If the renderer is displaying a log
488 // file, the message will be ignored. Note that this can be called from any
490 void SendJavascriptCommand(const std::string& command, base::Value* arg);
493 friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>;
494 friend class base::DeleteHelper<IOThreadImpl>;
496 typedef std::list<scoped_refptr<net::URLRequestContextGetter> >
499 virtual ~IOThreadImpl();
501 // Adds |entry| to the queue of pending log entries to be sent to the page via
502 // Javascript. Must be called on the IO Thread. Also creates a delayed task
503 // that will call PostPendingEntries, if there isn't one already.
504 void AddEntryToQueue(base::Value* entry);
506 // Sends all pending entries to the page via Javascript, and clears the list
507 // of pending entries. Sending multiple entries at once results in a
508 // significant reduction of CPU usage when a lot of events are happening.
509 // Must be called on the IO Thread.
510 void PostPendingEntries();
512 // Adds entries with the states of ongoing URL requests.
513 void PrePopulateEventList();
515 net::URLRequestContext* GetMainContext() {
516 return main_context_getter_->GetURLRequestContext();
519 // Pointer to the UI-thread message handler. Only access this from
521 base::WeakPtr<NetInternalsMessageHandler> handler_;
523 // The global IOThread, which contains the global NetLog to observer.
524 IOThread* io_thread_;
526 // The main URLRequestContextGetter for the tab's profile.
527 scoped_refptr<net::URLRequestContextGetter> main_context_getter_;
529 // Helper that runs the suite of connection tests.
530 scoped_ptr<ConnectionTester> connection_tester_;
532 // True if the Web UI has been deleted. This is used to prevent calling
533 // Javascript functions after the Web UI is destroyed. On refresh, the
534 // messages can end up being sent to the refreshed page, causing duplicate
535 // or partial entries.
537 // This is only read and written to on the UI thread.
538 bool was_webui_deleted_;
540 // Log entries that have yet to be passed along to Javascript page. Non-NULL
541 // when and only when there is a pending delayed task to call
542 // PostPendingEntries. Read and written to exclusively on the IO Thread.
543 scoped_ptr<base::ListValue> pending_entries_;
545 // Used for getting current status of URLRequests when net-internals is
546 // opened. |main_context_getter_| is automatically added on construction.
547 // Duplicates are allowed.
548 ContextGetterList context_getters_;
550 DISALLOW_COPY_AND_ASSIGN(IOThreadImpl);
553 ////////////////////////////////////////////////////////////////////////////////
555 // NetInternalsMessageHandler
557 ////////////////////////////////////////////////////////////////////////////////
559 NetInternalsMessageHandler::NetInternalsMessageHandler() {}
561 NetInternalsMessageHandler::~NetInternalsMessageHandler() {
563 proxy_.get()->OnWebUIDeleted();
564 // Notify the handler on the IO thread that the renderer is gone.
565 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
566 base::Bind(&IOThreadImpl::Detach, proxy_.get()));
570 void NetInternalsMessageHandler::RegisterMessages() {
571 DCHECK_CURRENTLY_ON(BrowserThread::UI);
573 Profile* profile = Profile::FromWebUI(web_ui());
575 proxy_ = new IOThreadImpl(this->AsWeakPtr(), g_browser_process->io_thread(),
576 profile->GetRequestContext());
577 proxy_->AddRequestContextGetter(profile->GetMediaRequestContext());
578 proxy_->AddRequestContextGetter(profile->GetRequestContextForExtensions());
579 #if defined(OS_CHROMEOS)
580 syslogs_getter_.reset(new SystemLogsGetter(this,
581 chromeos::system::SyslogsProvider::GetInstance()));
584 prerender::PrerenderManager* prerender_manager =
585 prerender::PrerenderManagerFactory::GetForProfile(profile);
586 if (prerender_manager) {
587 prerender_manager_ = prerender_manager->AsWeakPtr();
589 prerender_manager_ = base::WeakPtr<prerender::PrerenderManager>();
592 web_ui()->RegisterMessageCallback(
594 base::Bind(&NetInternalsMessageHandler::OnRendererReady,
595 base::Unretained(this)));
596 web_ui()->RegisterMessageCallback(
598 base::Bind(&IOThreadImpl::CallbackHelper,
599 &IOThreadImpl::OnGetProxySettings, proxy_));
600 web_ui()->RegisterMessageCallback(
601 "reloadProxySettings",
602 base::Bind(&IOThreadImpl::CallbackHelper,
603 &IOThreadImpl::OnReloadProxySettings, proxy_));
604 web_ui()->RegisterMessageCallback(
606 base::Bind(&IOThreadImpl::CallbackHelper,
607 &IOThreadImpl::OnGetBadProxies, proxy_));
608 web_ui()->RegisterMessageCallback(
610 base::Bind(&IOThreadImpl::CallbackHelper,
611 &IOThreadImpl::OnClearBadProxies, proxy_));
612 web_ui()->RegisterMessageCallback(
613 "getHostResolverInfo",
614 base::Bind(&IOThreadImpl::CallbackHelper,
615 &IOThreadImpl::OnGetHostResolverInfo, proxy_));
616 web_ui()->RegisterMessageCallback(
617 "clearHostResolverCache",
618 base::Bind(&IOThreadImpl::CallbackHelper,
619 &IOThreadImpl::OnClearHostResolverCache, proxy_));
620 web_ui()->RegisterMessageCallback(
622 base::Bind(&IOThreadImpl::CallbackHelper,
623 &IOThreadImpl::OnEnableIPv6, proxy_));
624 web_ui()->RegisterMessageCallback(
625 "startConnectionTests",
626 base::Bind(&IOThreadImpl::CallbackHelper,
627 &IOThreadImpl::OnStartConnectionTests, proxy_));
628 web_ui()->RegisterMessageCallback(
630 base::Bind(&IOThreadImpl::CallbackHelper,
631 &IOThreadImpl::OnHSTSQuery, proxy_));
632 web_ui()->RegisterMessageCallback(
634 base::Bind(&IOThreadImpl::CallbackHelper,
635 &IOThreadImpl::OnHSTSAdd, proxy_));
636 web_ui()->RegisterMessageCallback(
638 base::Bind(&IOThreadImpl::CallbackHelper,
639 &IOThreadImpl::OnHSTSDelete, proxy_));
640 web_ui()->RegisterMessageCallback(
642 base::Bind(&IOThreadImpl::CallbackHelper,
643 &IOThreadImpl::OnGetHttpCacheInfo, proxy_));
644 web_ui()->RegisterMessageCallback(
646 base::Bind(&IOThreadImpl::CallbackHelper,
647 &IOThreadImpl::OnGetSocketPoolInfo, proxy_));
648 web_ui()->RegisterMessageCallback(
649 "getSessionNetworkStats",
650 base::Bind(&IOThreadImpl::CallbackHelper,
651 &IOThreadImpl::OnGetSessionNetworkStats, proxy_));
652 web_ui()->RegisterMessageCallback(
654 base::Bind(&IOThreadImpl::CallbackHelper,
655 &IOThreadImpl::OnCloseIdleSockets, proxy_));
656 web_ui()->RegisterMessageCallback(
658 base::Bind(&IOThreadImpl::CallbackHelper,
659 &IOThreadImpl::OnFlushSocketPools, proxy_));
660 web_ui()->RegisterMessageCallback(
661 "getSpdySessionInfo",
662 base::Bind(&IOThreadImpl::CallbackHelper,
663 &IOThreadImpl::OnGetSpdySessionInfo, proxy_));
664 web_ui()->RegisterMessageCallback(
666 base::Bind(&IOThreadImpl::CallbackHelper,
667 &IOThreadImpl::OnGetSpdyStatus, proxy_));
668 web_ui()->RegisterMessageCallback(
669 "getSpdyAlternateProtocolMappings",
670 base::Bind(&IOThreadImpl::CallbackHelper,
671 &IOThreadImpl::OnGetSpdyAlternateProtocolMappings, proxy_));
672 web_ui()->RegisterMessageCallback(
674 base::Bind(&IOThreadImpl::CallbackHelper,
675 &IOThreadImpl::OnGetQuicInfo, proxy_));
677 web_ui()->RegisterMessageCallback(
678 "getServiceProviders",
679 base::Bind(&IOThreadImpl::CallbackHelper,
680 &IOThreadImpl::OnGetServiceProviders, proxy_));
683 web_ui()->RegisterMessageCallback(
685 base::Bind(&IOThreadImpl::CallbackHelper,
686 &IOThreadImpl::OnSetLogLevel, proxy_));
687 web_ui()->RegisterMessageCallback(
689 base::Bind(&NetInternalsMessageHandler::OnClearBrowserCache,
690 base::Unretained(this)));
691 web_ui()->RegisterMessageCallback(
693 base::Bind(&NetInternalsMessageHandler::OnGetPrerenderInfo,
694 base::Unretained(this)));
695 web_ui()->RegisterMessageCallback(
696 "getHistoricNetworkStats",
697 base::Bind(&NetInternalsMessageHandler::OnGetHistoricNetworkStats,
698 base::Unretained(this)));
699 web_ui()->RegisterMessageCallback(
701 base::Bind(&NetInternalsMessageHandler::OnGetExtensionInfo,
702 base::Unretained(this)));
703 #if defined(OS_CHROMEOS)
704 web_ui()->RegisterMessageCallback(
706 base::Bind(&NetInternalsMessageHandler::OnRefreshSystemLogs,
707 base::Unretained(this)));
708 web_ui()->RegisterMessageCallback(
710 base::Bind(&NetInternalsMessageHandler::OnGetSystemLog,
711 base::Unretained(this)));
712 web_ui()->RegisterMessageCallback(
714 base::Bind(&NetInternalsMessageHandler::OnImportONCFile,
715 base::Unretained(this)));
716 web_ui()->RegisterMessageCallback(
718 base::Bind(&NetInternalsMessageHandler::OnStoreDebugLogs,
719 base::Unretained(this)));
720 web_ui()->RegisterMessageCallback(
721 "setNetworkDebugMode",
722 base::Bind(&NetInternalsMessageHandler::OnSetNetworkDebugMode,
723 base::Unretained(this)));
727 void NetInternalsMessageHandler::SendJavascriptCommand(
728 const std::string& command,
730 scoped_ptr<base::Value> command_value(new base::StringValue(command));
731 scoped_ptr<base::Value> value(arg);
732 DCHECK_CURRENTLY_ON(BrowserThread::UI);
734 web_ui()->CallJavascriptFunction("g_browser.receive",
735 *command_value.get(),
738 web_ui()->CallJavascriptFunction("g_browser.receive",
739 *command_value.get());
743 void NetInternalsMessageHandler::OnRendererReady(const base::ListValue* list) {
744 IOThreadImpl::CallbackHelper(&IOThreadImpl::OnRendererReady, proxy_, list);
747 void NetInternalsMessageHandler::OnClearBrowserCache(
748 const base::ListValue* list) {
749 BrowsingDataRemover* remover = BrowsingDataRemover::CreateForUnboundedRange(
750 Profile::FromWebUI(web_ui()));
751 remover->Remove(BrowsingDataRemover::REMOVE_CACHE,
752 BrowsingDataHelper::UNPROTECTED_WEB);
753 // BrowsingDataRemover deletes itself.
756 void NetInternalsMessageHandler::OnGetPrerenderInfo(
757 const base::ListValue* list) {
758 DCHECK_CURRENTLY_ON(BrowserThread::UI);
760 base::DictionaryValue* value = NULL;
761 prerender::PrerenderManager* prerender_manager = prerender_manager_.get();
762 if (!prerender_manager) {
763 value = new base::DictionaryValue();
764 value->SetBoolean("enabled", false);
765 value->SetBoolean("omnibox_enabled", false);
767 value = prerender_manager->GetAsValue();
769 SendJavascriptCommand("receivedPrerenderInfo", value);
772 void NetInternalsMessageHandler::OnGetHistoricNetworkStats(
773 const base::ListValue* list) {
774 DCHECK_CURRENTLY_ON(BrowserThread::UI);
775 base::Value* historic_network_info =
776 ChromeNetworkDelegate::HistoricNetworkStatsInfoToValue();
777 SendJavascriptCommand("receivedHistoricNetworkStats", historic_network_info);
780 void NetInternalsMessageHandler::OnGetExtensionInfo(
781 const base::ListValue* list) {
782 DCHECK_CURRENTLY_ON(BrowserThread::UI);
783 base::ListValue* extension_list = new base::ListValue();
784 Profile* profile = Profile::FromWebUI(web_ui());
785 extensions::ExtensionSystem* extension_system =
786 extensions::ExtensionSystem::Get(profile);
787 if (extension_system) {
788 ExtensionService* extension_service = extension_system->extension_service();
789 if (extension_service) {
790 scoped_ptr<const extensions::ExtensionSet> extensions(
791 extensions::ExtensionRegistry::Get(profile)
792 ->GenerateInstalledExtensionsSet());
793 for (extensions::ExtensionSet::const_iterator it = extensions->begin();
794 it != extensions->end(); ++it) {
795 base::DictionaryValue* extension_info = new base::DictionaryValue();
796 bool enabled = extension_service->IsExtensionEnabled((*it)->id());
797 extensions::GetExtensionBasicInfo(it->get(), enabled, extension_info);
798 extension_list->Append(extension_info);
802 SendJavascriptCommand("receivedExtensionInfo", extension_list);
805 #if defined(OS_CHROMEOS)
806 ////////////////////////////////////////////////////////////////////////////////
808 // NetInternalsMessageHandler::SystemLogsGetter
810 ////////////////////////////////////////////////////////////////////////////////
812 NetInternalsMessageHandler::SystemLogsGetter::SystemLogsGetter(
813 NetInternalsMessageHandler* handler,
814 chromeos::system::SyslogsProvider* syslogs_provider)
816 syslogs_provider_(syslogs_provider),
817 logs_received_(false),
818 logs_requested_(false) {
819 if (!syslogs_provider_)
820 LOG(ERROR) << "System access library not loaded";
823 NetInternalsMessageHandler::SystemLogsGetter::~SystemLogsGetter() {
827 void NetInternalsMessageHandler::SystemLogsGetter::DeleteSystemLogs() {
828 if (syslogs_provider_ && logs_requested_ && !logs_received_) {
829 tracker_.TryCancel(syslogs_task_id_);
831 logs_requested_ = false;
832 logs_received_ = false;
836 void NetInternalsMessageHandler::SystemLogsGetter::RequestSystemLog(
837 const base::ListValue* args) {
838 if (!logs_requested_) {
839 DCHECK(!logs_received_);
842 SystemLogRequest log_request;
843 args->GetString(0, &log_request.log_key);
844 args->GetString(1, &log_request.cell_id);
846 if (logs_received_) {
847 SendLogs(log_request);
849 requests_.push_back(log_request);
853 void NetInternalsMessageHandler::SystemLogsGetter::LoadSystemLogs() {
854 if (logs_requested_ || !syslogs_provider_)
856 logs_requested_ = true;
857 syslogs_task_id_ = syslogs_provider_->RequestSyslogs(
858 false, // compress logs.
859 chromeos::system::SyslogsProvider::SYSLOGS_NETWORK,
861 &NetInternalsMessageHandler::SystemLogsGetter::OnSystemLogsLoaded,
862 base::Unretained(this)),
866 void NetInternalsMessageHandler::SystemLogsGetter::OnSystemLogsLoaded(
867 chromeos::system::LogDictionaryType* sys_info,
868 std::string* ignored_content) {
869 DCHECK(!ignored_content);
870 logs_.reset(sys_info);
871 logs_received_ = true;
872 for (std::list<SystemLogRequest>::iterator request_it = requests_.begin();
873 request_it != requests_.end();
875 SendLogs(*request_it);
880 void NetInternalsMessageHandler::SystemLogsGetter::SendLogs(
881 const SystemLogRequest& request) {
882 base::DictionaryValue* result = new base::DictionaryValue();
883 chromeos::system::LogDictionaryType::iterator log_it =
884 logs_->find(request.log_key);
885 if (log_it != logs_->end()) {
886 if (!log_it->second.empty()) {
887 result->SetString("log", log_it->second);
889 result->SetString("log", "<no relevant lines found>");
892 result->SetString("log", "<invalid log name>");
894 result->SetString("cellId", request.cell_id);
896 handler_->SendJavascriptCommand("getSystemLogCallback", result);
898 #endif // defined(OS_CHROMEOS)
900 ////////////////////////////////////////////////////////////////////////////////
902 // NetInternalsMessageHandler::IOThreadImpl
904 ////////////////////////////////////////////////////////////////////////////////
906 NetInternalsMessageHandler::IOThreadImpl::IOThreadImpl(
907 const base::WeakPtr<NetInternalsMessageHandler>& handler,
909 net::URLRequestContextGetter* main_context_getter)
911 io_thread_(io_thread),
912 main_context_getter_(main_context_getter),
913 was_webui_deleted_(false) {
914 DCHECK_CURRENTLY_ON(BrowserThread::UI);
915 AddRequestContextGetter(main_context_getter);
918 NetInternalsMessageHandler::IOThreadImpl::~IOThreadImpl() {
919 DCHECK_CURRENTLY_ON(BrowserThread::UI);
922 void NetInternalsMessageHandler::IOThreadImpl::AddRequestContextGetter(
923 net::URLRequestContextGetter* context_getter) {
924 DCHECK_CURRENTLY_ON(BrowserThread::UI);
925 context_getters_.push_back(context_getter);
928 void NetInternalsMessageHandler::IOThreadImpl::CallbackHelper(
929 MessageHandler method,
930 scoped_refptr<IOThreadImpl> io_thread,
931 const base::ListValue* list) {
932 DCHECK_CURRENTLY_ON(BrowserThread::UI);
934 // We need to make a copy of the value in order to pass it over to the IO
935 // thread. |list_copy| will be deleted when the task is destroyed. The called
936 // |method| cannot take ownership of |list_copy|.
937 base::ListValue* list_copy =
938 (list && list->GetSize()) ? list->DeepCopy() : NULL;
940 BrowserThread::PostTask(
941 BrowserThread::IO, FROM_HERE,
942 base::Bind(method, io_thread, base::Owned(list_copy)));
945 void NetInternalsMessageHandler::IOThreadImpl::Detach() {
946 DCHECK_CURRENTLY_ON(BrowserThread::IO);
947 // Unregister with network stack to observe events.
949 net_log()->RemoveThreadSafeObserver(this);
951 // Cancel any in-progress connection tests.
952 connection_tester_.reset();
955 void NetInternalsMessageHandler::IOThreadImpl::OnWebUIDeleted() {
956 DCHECK_CURRENTLY_ON(BrowserThread::UI);
957 was_webui_deleted_ = true;
960 void NetInternalsMessageHandler::IOThreadImpl::OnRendererReady(
961 const base::ListValue* list) {
962 DCHECK_CURRENTLY_ON(BrowserThread::IO);
964 // If we have any pending entries, go ahead and get rid of them, so they won't
965 // appear before the REQUEST_ALIVE events we add for currently active
967 PostPendingEntries();
969 SendJavascriptCommand("receivedConstants", NetInternalsUI::GetConstants());
971 // Add entries for ongoing URL requests.
972 PrePopulateEventList();
975 // Register with network stack to observe events.
976 io_thread_->net_log()->AddThreadSafeObserver(this,
977 net::NetLog::LOG_ALL_BUT_BYTES);
981 void NetInternalsMessageHandler::IOThreadImpl::OnGetProxySettings(
982 const base::ListValue* list) {
984 net::ProxyService* proxy_service = GetMainContext()->proxy_service();
986 base::DictionaryValue* dict = new base::DictionaryValue();
987 if (proxy_service->fetched_config().is_valid())
988 dict->Set("original", proxy_service->fetched_config().ToValue());
989 if (proxy_service->config().is_valid())
990 dict->Set("effective", proxy_service->config().ToValue());
992 SendJavascriptCommand("receivedProxySettings", dict);
995 void NetInternalsMessageHandler::IOThreadImpl::OnReloadProxySettings(
996 const base::ListValue* list) {
998 GetMainContext()->proxy_service()->ForceReloadProxyConfig();
1000 // Cause the renderer to be notified of the new values.
1001 OnGetProxySettings(NULL);
1004 void NetInternalsMessageHandler::IOThreadImpl::OnGetBadProxies(
1005 const base::ListValue* list) {
1008 const net::ProxyRetryInfoMap& bad_proxies_map =
1009 GetMainContext()->proxy_service()->proxy_retry_info();
1011 base::ListValue* dict_list = new base::ListValue();
1013 for (net::ProxyRetryInfoMap::const_iterator it = bad_proxies_map.begin();
1014 it != bad_proxies_map.end(); ++it) {
1015 const std::string& proxy_uri = it->first;
1016 const net::ProxyRetryInfo& retry_info = it->second;
1018 base::DictionaryValue* dict = new base::DictionaryValue();
1019 dict->SetString("proxy_uri", proxy_uri);
1020 dict->SetString("bad_until",
1021 net::NetLog::TickCountToString(retry_info.bad_until));
1023 dict_list->Append(dict);
1026 SendJavascriptCommand("receivedBadProxies", dict_list);
1029 void NetInternalsMessageHandler::IOThreadImpl::OnClearBadProxies(
1030 const base::ListValue* list) {
1032 GetMainContext()->proxy_service()->ClearBadProxiesCache();
1034 // Cause the renderer to be notified of the new values.
1035 OnGetBadProxies(NULL);
1038 void NetInternalsMessageHandler::IOThreadImpl::OnGetHostResolverInfo(
1039 const base::ListValue* list) {
1041 net::URLRequestContext* context = GetMainContext();
1042 net::HostCache* cache = GetHostResolverCache(context);
1045 SendJavascriptCommand("receivedHostResolverInfo", NULL);
1049 base::DictionaryValue* dict = new base::DictionaryValue();
1051 base::Value* dns_config = context->host_resolver()->GetDnsConfigAsValue();
1053 dict->Set("dns_config", dns_config);
1056 "default_address_family",
1057 static_cast<int>(context->host_resolver()->GetDefaultAddressFamily()));
1059 base::DictionaryValue* cache_info_dict = new base::DictionaryValue();
1061 cache_info_dict->SetInteger(
1063 static_cast<int>(cache->max_entries()));
1065 base::ListValue* entry_list = new base::ListValue();
1067 net::HostCache::EntryMap::Iterator it(cache->entries());
1068 for (; it.HasNext(); it.Advance()) {
1069 const net::HostCache::Key& key = it.key();
1070 const net::HostCache::Entry& entry = it.value();
1072 base::DictionaryValue* entry_dict = new base::DictionaryValue();
1074 entry_dict->SetString("hostname", key.hostname);
1075 entry_dict->SetInteger("address_family",
1076 static_cast<int>(key.address_family));
1077 entry_dict->SetString("expiration",
1078 net::NetLog::TickCountToString(it.expiration()));
1080 if (entry.error != net::OK) {
1081 entry_dict->SetInteger("error", entry.error);
1083 // Append all of the resolved addresses.
1084 base::ListValue* address_list = new base::ListValue();
1085 for (size_t i = 0; i < entry.addrlist.size(); ++i) {
1086 address_list->AppendString(entry.addrlist[i].ToStringWithoutPort());
1088 entry_dict->Set("addresses", address_list);
1091 entry_list->Append(entry_dict);
1094 cache_info_dict->Set("entries", entry_list);
1095 dict->Set("cache", cache_info_dict);
1097 SendJavascriptCommand("receivedHostResolverInfo", dict);
1100 void NetInternalsMessageHandler::IOThreadImpl::OnClearHostResolverCache(
1101 const base::ListValue* list) {
1103 net::HostCache* cache = GetHostResolverCache(GetMainContext());
1108 // Cause the renderer to be notified of the new values.
1109 OnGetHostResolverInfo(NULL);
1112 void NetInternalsMessageHandler::IOThreadImpl::OnEnableIPv6(
1113 const base::ListValue* list) {
1115 net::HostResolver* host_resolver = GetMainContext()->host_resolver();
1117 host_resolver->SetDefaultAddressFamily(net::ADDRESS_FAMILY_UNSPECIFIED);
1119 // Cause the renderer to be notified of the new value.
1120 OnGetHostResolverInfo(NULL);
1123 void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTests(
1124 const base::ListValue* list) {
1125 // |value| should be: [<URL to test>].
1126 base::string16 url_str;
1127 CHECK(list->GetString(0, &url_str));
1129 // Try to fix-up the user provided URL into something valid.
1130 // For example, turn "www.google.com" into "http://www.google.com".
1131 GURL url(url_fixer::FixupURL(base::UTF16ToUTF8(url_str), std::string()));
1133 connection_tester_.reset(new ConnectionTester(
1135 io_thread_->globals()->proxy_script_fetcher_context.get(),
1137 connection_tester_->RunAllTests(url);
1140 void NetInternalsMessageHandler::IOThreadImpl::OnHSTSQuery(
1141 const base::ListValue* list) {
1142 // |list| should be: [<domain to query>].
1144 CHECK(list->GetString(0, &domain));
1145 base::DictionaryValue* result = new base::DictionaryValue();
1147 if (!base::IsStringASCII(domain)) {
1148 result->SetString("error", "non-ASCII domain name");
1150 net::TransportSecurityState* transport_security_state =
1151 GetMainContext()->transport_security_state();
1152 if (!transport_security_state) {
1153 result->SetString("error", "no TransportSecurityState active");
1155 net::TransportSecurityState::DomainState static_state;
1156 const bool found_static = transport_security_state->GetStaticDomainState(
1157 domain, true, &static_state);
1159 result->SetBoolean("has_static_sts",
1160 found_static && static_state.ShouldUpgradeToSSL());
1161 result->SetInteger("static_upgrade_mode",
1162 static_cast<int>(static_state.sts.upgrade_mode));
1163 result->SetBoolean("static_sts_include_subdomains",
1164 static_state.sts.include_subdomains);
1165 result->SetDouble("static_sts_observed",
1166 static_state.sts.last_observed.ToDoubleT());
1167 result->SetDouble("static_sts_expiry",
1168 static_state.sts.expiry.ToDoubleT());
1169 result->SetBoolean("has_static_pkp",
1170 found_static && static_state.HasPublicKeyPins());
1171 result->SetBoolean("static_pkp_include_subdomains",
1172 static_state.pkp.include_subdomains);
1173 result->SetDouble("static_pkp_observed",
1174 static_state.pkp.last_observed.ToDoubleT());
1175 result->SetDouble("static_pkp_expiry",
1176 static_state.pkp.expiry.ToDoubleT());
1177 result->SetString("static_spki_hashes",
1178 HashesToBase64String(static_state.pkp.spki_hashes));
1181 net::TransportSecurityState::DomainState dynamic_state;
1182 const bool found_dynamic =
1183 transport_security_state->GetDynamicDomainState(domain,
1185 if (found_dynamic) {
1186 result->SetInteger("dynamic_upgrade_mode",
1187 static_cast<int>(dynamic_state.sts.upgrade_mode));
1188 result->SetBoolean("dynamic_sts_include_subdomains",
1189 dynamic_state.sts.include_subdomains);
1190 result->SetBoolean("dynamic_pkp_include_subdomains",
1191 dynamic_state.pkp.include_subdomains);
1192 result->SetDouble("dynamic_sts_observed",
1193 dynamic_state.sts.last_observed.ToDoubleT());
1194 result->SetDouble("dynamic_pkp_observed",
1195 dynamic_state.pkp.last_observed.ToDoubleT());
1196 result->SetDouble("dynamic_sts_expiry",
1197 dynamic_state.sts.expiry.ToDoubleT());
1198 result->SetDouble("dynamic_pkp_expiry",
1199 dynamic_state.pkp.expiry.ToDoubleT());
1200 result->SetString("dynamic_spki_hashes",
1201 HashesToBase64String(dynamic_state.pkp.spki_hashes));
1204 result->SetBoolean("result", found_static || found_dynamic);
1206 result->SetString("domain", static_state.domain);
1207 } else if (found_dynamic) {
1208 result->SetString("domain", dynamic_state.domain);
1210 result->SetString("domain", domain);
1215 SendJavascriptCommand("receivedHSTSResult", result);
1218 void NetInternalsMessageHandler::IOThreadImpl::OnHSTSAdd(
1219 const base::ListValue* list) {
1220 // |list| should be: [<domain to query>, <STS include subdomains>, <PKP
1221 // include subdomains>, <key pins>].
1223 CHECK(list->GetString(0, &domain));
1224 if (!base::IsStringASCII(domain)) {
1225 // Silently fail. The user will get a helpful error if they query for the
1229 bool sts_include_subdomains;
1230 CHECK(list->GetBoolean(1, &sts_include_subdomains));
1231 bool pkp_include_subdomains;
1232 CHECK(list->GetBoolean(2, &pkp_include_subdomains));
1233 std::string hashes_str;
1234 CHECK(list->GetString(3, &hashes_str));
1236 net::TransportSecurityState* transport_security_state =
1237 GetMainContext()->transport_security_state();
1238 if (!transport_security_state)
1241 base::Time expiry = base::Time::Now() + base::TimeDelta::FromDays(1000);
1242 net::HashValueVector hashes;
1243 if (!hashes_str.empty()) {
1244 if (!Base64StringToHashes(hashes_str, &hashes))
1248 transport_security_state->AddHSTS(domain, expiry, sts_include_subdomains);
1249 transport_security_state->AddHPKP(domain, expiry, pkp_include_subdomains,
1253 void NetInternalsMessageHandler::IOThreadImpl::OnHSTSDelete(
1254 const base::ListValue* list) {
1255 // |list| should be: [<domain to query>].
1257 CHECK(list->GetString(0, &domain));
1258 if (!base::IsStringASCII(domain)) {
1259 // There cannot be a unicode entry in the HSTS set.
1262 net::TransportSecurityState* transport_security_state =
1263 GetMainContext()->transport_security_state();
1264 if (!transport_security_state)
1267 transport_security_state->DeleteDynamicDataForHost(domain);
1270 void NetInternalsMessageHandler::IOThreadImpl::OnGetHttpCacheInfo(
1271 const base::ListValue* list) {
1273 base::DictionaryValue* info_dict = new base::DictionaryValue();
1274 base::DictionaryValue* stats_dict = new base::DictionaryValue();
1276 disk_cache::Backend* disk_cache = GetDiskCacheBackend(GetMainContext());
1279 // Extract the statistics key/value pairs from the backend.
1280 std::vector<std::pair<std::string, std::string> > stats;
1281 disk_cache->GetStats(&stats);
1282 for (size_t i = 0; i < stats.size(); ++i) {
1283 stats_dict->SetStringWithoutPathExpansion(
1284 stats[i].first, stats[i].second);
1288 info_dict->Set("stats", stats_dict);
1290 SendJavascriptCommand("receivedHttpCacheInfo", info_dict);
1293 void NetInternalsMessageHandler::IOThreadImpl::OnGetSocketPoolInfo(
1294 const base::ListValue* list) {
1296 net::HttpNetworkSession* http_network_session =
1297 GetHttpNetworkSession(GetMainContext());
1299 base::Value* socket_pool_info = NULL;
1300 if (http_network_session)
1301 socket_pool_info = http_network_session->SocketPoolInfoToValue();
1303 SendJavascriptCommand("receivedSocketPoolInfo", socket_pool_info);
1306 void NetInternalsMessageHandler::IOThreadImpl::OnGetSessionNetworkStats(
1307 const base::ListValue* list) {
1309 net::HttpNetworkSession* http_network_session =
1310 GetHttpNetworkSession(main_context_getter_->GetURLRequestContext());
1312 base::Value* network_info = NULL;
1313 if (http_network_session) {
1314 ChromeNetworkDelegate* net_delegate =
1315 static_cast<ChromeNetworkDelegate*>(
1316 http_network_session->network_delegate());
1318 network_info = net_delegate->SessionNetworkStatsInfoToValue();
1321 SendJavascriptCommand("receivedSessionNetworkStats", network_info);
1324 void NetInternalsMessageHandler::IOThreadImpl::OnFlushSocketPools(
1325 const base::ListValue* list) {
1327 net::HttpNetworkSession* http_network_session =
1328 GetHttpNetworkSession(GetMainContext());
1330 if (http_network_session)
1331 http_network_session->CloseAllConnections();
1334 void NetInternalsMessageHandler::IOThreadImpl::OnCloseIdleSockets(
1335 const base::ListValue* list) {
1337 net::HttpNetworkSession* http_network_session =
1338 GetHttpNetworkSession(GetMainContext());
1340 if (http_network_session)
1341 http_network_session->CloseIdleConnections();
1344 void NetInternalsMessageHandler::IOThreadImpl::OnGetSpdySessionInfo(
1345 const base::ListValue* list) {
1347 net::HttpNetworkSession* http_network_session =
1348 GetHttpNetworkSession(GetMainContext());
1350 base::Value* spdy_info = http_network_session ?
1351 http_network_session->SpdySessionPoolInfoToValue() : NULL;
1352 SendJavascriptCommand("receivedSpdySessionInfo", spdy_info);
1355 void NetInternalsMessageHandler::IOThreadImpl::OnGetSpdyStatus(
1356 const base::ListValue* list) {
1358 base::DictionaryValue* status_dict = new base::DictionaryValue();
1360 net::HttpNetworkSession* http_network_session =
1361 GetHttpNetworkSession(GetMainContext());
1363 status_dict->Set("spdy_enabled",
1364 base::Value::CreateBooleanValue(
1365 net::HttpStreamFactory::spdy_enabled()));
1366 status_dict->Set("use_alternate_protocols",
1367 base::Value::CreateBooleanValue(
1368 http_network_session->params().use_alternate_protocols));
1369 status_dict->Set("force_spdy_over_ssl",
1370 base::Value::CreateBooleanValue(
1371 http_network_session->params().force_spdy_over_ssl));
1372 status_dict->Set("force_spdy_always",
1373 base::Value::CreateBooleanValue(
1374 http_network_session->params().force_spdy_always));
1376 std::vector<std::string> next_protos;
1377 http_network_session->GetNextProtos(&next_protos);
1378 std::string next_protos_string = JoinString(next_protos, ',');
1379 status_dict->SetString("next_protos", next_protos_string);
1381 SendJavascriptCommand("receivedSpdyStatus", status_dict);
1385 NetInternalsMessageHandler::IOThreadImpl::OnGetSpdyAlternateProtocolMappings(
1386 const base::ListValue* list) {
1388 base::ListValue* dict_list = new base::ListValue();
1390 const net::HttpServerProperties& http_server_properties =
1391 *GetMainContext()->http_server_properties();
1393 const net::AlternateProtocolMap& map =
1394 http_server_properties.alternate_protocol_map();
1396 for (net::AlternateProtocolMap::const_iterator it = map.begin();
1397 it != map.end(); ++it) {
1398 base::DictionaryValue* dict = new base::DictionaryValue();
1399 dict->SetString("host_port_pair", it->first.ToString());
1400 dict->SetString("alternate_protocol", it->second.ToString());
1401 dict_list->Append(dict);
1404 SendJavascriptCommand("receivedSpdyAlternateProtocolMappings", dict_list);
1407 void NetInternalsMessageHandler::IOThreadImpl::OnGetQuicInfo(
1408 const base::ListValue* list) {
1410 net::HttpNetworkSession* http_network_session =
1411 GetHttpNetworkSession(GetMainContext());
1413 base::Value* quic_info = http_network_session ?
1414 http_network_session->QuicInfoToValue() : NULL;
1415 SendJavascriptCommand("receivedQuicInfo", quic_info);
1419 void NetInternalsMessageHandler::IOThreadImpl::OnGetServiceProviders(
1420 const base::ListValue* list) {
1423 base::DictionaryValue* service_providers = new base::DictionaryValue();
1425 WinsockLayeredServiceProviderList layered_providers;
1426 GetWinsockLayeredServiceProviders(&layered_providers);
1427 base::ListValue* layered_provider_list = new base::ListValue();
1428 for (size_t i = 0; i < layered_providers.size(); ++i) {
1429 base::DictionaryValue* service_dict = new base::DictionaryValue();
1430 service_dict->SetString("name", layered_providers[i].name);
1431 service_dict->SetInteger("version", layered_providers[i].version);
1432 service_dict->SetInteger("chain_length", layered_providers[i].chain_length);
1433 service_dict->SetInteger("socket_type", layered_providers[i].socket_type);
1434 service_dict->SetInteger("socket_protocol",
1435 layered_providers[i].socket_protocol);
1436 service_dict->SetString("path", layered_providers[i].path);
1438 layered_provider_list->Append(service_dict);
1440 service_providers->Set("service_providers", layered_provider_list);
1442 WinsockNamespaceProviderList namespace_providers;
1443 GetWinsockNamespaceProviders(&namespace_providers);
1444 base::ListValue* namespace_list = new base::ListValue;
1445 for (size_t i = 0; i < namespace_providers.size(); ++i) {
1446 base::DictionaryValue* namespace_dict = new base::DictionaryValue();
1447 namespace_dict->SetString("name", namespace_providers[i].name);
1448 namespace_dict->SetBoolean("active", namespace_providers[i].active);
1449 namespace_dict->SetInteger("version", namespace_providers[i].version);
1450 namespace_dict->SetInteger("type", namespace_providers[i].type);
1452 namespace_list->Append(namespace_dict);
1454 service_providers->Set("namespace_providers", namespace_list);
1456 SendJavascriptCommand("receivedServiceProviders", service_providers);
1460 #if defined(OS_CHROMEOS)
1461 void NetInternalsMessageHandler::OnRefreshSystemLogs(
1462 const base::ListValue* list) {
1464 DCHECK(syslogs_getter_.get());
1465 syslogs_getter_->DeleteSystemLogs();
1466 syslogs_getter_->LoadSystemLogs();
1469 void NetInternalsMessageHandler::OnGetSystemLog(
1470 const base::ListValue* list) {
1471 DCHECK(syslogs_getter_.get());
1472 syslogs_getter_->RequestSystemLog(list);
1475 void NetInternalsMessageHandler::ImportONCFileToNSSDB(
1476 const std::string& onc_blob,
1477 const std::string& passcode,
1478 net::NSSCertDatabase* nssdb) {
1480 chromeos::User* user = chromeos::UserManager::Get()->GetUserByProfile(
1481 Profile::FromWebUI(web_ui()));
1484 onc::ONCSource onc_source = onc::ONC_SOURCE_USER_IMPORT;
1486 base::ListValue network_configs;
1487 base::DictionaryValue global_network_config;
1488 base::ListValue certificates;
1489 if (!chromeos::onc::ParseAndValidateOncForImport(onc_blob,
1493 &global_network_config,
1495 error = "Errors occurred during the ONC parsing. ";
1498 chromeos::onc::CertificateImporterImpl cert_importer(nssdb);
1499 if (!cert_importer.ImportCertificates(certificates, onc_source, NULL))
1500 error += "Some certificates couldn't be imported. ";
1502 std::string network_error;
1503 chromeos::onc::ImportNetworksForUser(user, network_configs, &network_error);
1504 if (!network_error.empty())
1505 error += network_error;
1507 error = "User not found.";
1510 LOG_IF(ERROR, !error.empty()) << error;
1511 SendJavascriptCommand("receivedONCFileParse", new base::StringValue(error));
1514 void NetInternalsMessageHandler::OnImportONCFile(
1515 const base::ListValue* list) {
1516 std::string onc_blob;
1517 std::string passcode;
1518 if (list->GetSize() != 2 ||
1519 !list->GetString(0, &onc_blob) ||
1520 !list->GetString(1, &passcode)) {
1524 GetNSSCertDatabaseForProfile(
1525 Profile::FromWebUI(web_ui()),
1526 base::Bind(&NetInternalsMessageHandler::ImportONCFileToNSSDB, AsWeakPtr(),
1527 onc_blob, passcode));
1530 void NetInternalsMessageHandler::OnStoreDebugLogs(const base::ListValue* list) {
1533 SendJavascriptCommand("receivedStoreDebugLogs",
1534 new base::StringValue("Creating log file..."));
1535 const DownloadPrefs* const prefs =
1536 DownloadPrefs::FromBrowserContext(Profile::FromWebUI(web_ui()));
1537 StoreDebugLogs(prefs->DownloadPath(),
1538 base::Bind(&NetInternalsMessageHandler::OnStoreDebugLogsCompleted,
1542 void NetInternalsMessageHandler::OnStoreDebugLogsCompleted(
1543 const base::FilePath& log_path, bool succeeded) {
1546 status = "Created log file: " + log_path.BaseName().AsUTF8Unsafe();
1548 status = "Failed to create log file";
1549 SendJavascriptCommand("receivedStoreDebugLogs",
1550 new base::StringValue(status));
1553 void NetInternalsMessageHandler::OnSetNetworkDebugMode(
1554 const base::ListValue* list) {
1555 std::string subsystem;
1556 if (list->GetSize() != 1 || !list->GetString(0, &subsystem))
1558 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->
1562 &NetInternalsMessageHandler::OnSetNetworkDebugModeCompleted,
1567 void NetInternalsMessageHandler::OnSetNetworkDebugModeCompleted(
1568 const std::string& subsystem,
1572 status = "Debug mode is changed to " + subsystem;
1574 status = "Failed to change debug mode to " + subsystem;
1575 SendJavascriptCommand("receivedSetNetworkDebugMode",
1576 new base::StringValue(status));
1578 #endif // defined(OS_CHROMEOS)
1580 void NetInternalsMessageHandler::IOThreadImpl::OnSetLogLevel(
1581 const base::ListValue* list) {
1583 std::string log_level_string;
1584 if (!list->GetString(0, &log_level_string) ||
1585 !base::StringToInt(log_level_string, &log_level)) {
1590 DCHECK_GE(log_level, net::NetLog::LOG_ALL);
1591 DCHECK_LT(log_level, net::NetLog::LOG_NONE);
1592 net_log()->SetObserverLogLevel(
1593 this, static_cast<net::NetLog::LogLevel>(log_level));
1596 // Note that unlike other methods of IOThreadImpl, this function
1597 // can be called from ANY THREAD.
1598 void NetInternalsMessageHandler::IOThreadImpl::OnAddEntry(
1599 const net::NetLog::Entry& entry) {
1600 BrowserThread::PostTask(
1601 BrowserThread::IO, FROM_HERE,
1602 base::Bind(&IOThreadImpl::AddEntryToQueue, this, entry.ToValue()));
1605 void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTestSuite() {
1606 SendJavascriptCommand("receivedStartConnectionTestSuite", NULL);
1609 void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTestExperiment(
1610 const ConnectionTester::Experiment& experiment) {
1611 SendJavascriptCommand(
1612 "receivedStartConnectionTestExperiment",
1613 ExperimentToValue(experiment));
1617 NetInternalsMessageHandler::IOThreadImpl::OnCompletedConnectionTestExperiment(
1618 const ConnectionTester::Experiment& experiment,
1620 base::DictionaryValue* dict = new base::DictionaryValue();
1622 dict->Set("experiment", ExperimentToValue(experiment));
1623 dict->SetInteger("result", result);
1625 SendJavascriptCommand(
1626 "receivedCompletedConnectionTestExperiment",
1631 NetInternalsMessageHandler::IOThreadImpl::OnCompletedConnectionTestSuite() {
1632 SendJavascriptCommand(
1633 "receivedCompletedConnectionTestSuite",
1637 // Note that this can be called from ANY THREAD.
1638 void NetInternalsMessageHandler::IOThreadImpl::SendJavascriptCommand(
1639 const std::string& command,
1641 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
1642 if (handler_.get() && !was_webui_deleted_) {
1643 // We check |handler_| in case it was deleted on the UI thread earlier
1644 // while we were running on the IO thread.
1645 handler_->SendJavascriptCommand(command, arg);
1652 if (!BrowserThread::PostTask(
1653 BrowserThread::UI, FROM_HERE,
1654 base::Bind(&IOThreadImpl::SendJavascriptCommand, this, command, arg))) {
1655 // Failed posting the task, avoid leaking.
1660 void NetInternalsMessageHandler::IOThreadImpl::AddEntryToQueue(
1661 base::Value* entry) {
1662 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1663 if (!pending_entries_.get()) {
1664 pending_entries_.reset(new base::ListValue());
1665 BrowserThread::PostDelayedTask(
1666 BrowserThread::IO, FROM_HERE,
1667 base::Bind(&IOThreadImpl::PostPendingEntries, this),
1668 base::TimeDelta::FromMilliseconds(kNetLogEventDelayMilliseconds));
1670 pending_entries_->Append(entry);
1673 void NetInternalsMessageHandler::IOThreadImpl::PostPendingEntries() {
1674 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1675 if (pending_entries_.get())
1676 SendJavascriptCommand("receivedLogEntries", pending_entries_.release());
1679 void NetInternalsMessageHandler::IOThreadImpl::PrePopulateEventList() {
1680 // Use a set to prevent duplicates.
1681 std::set<net::URLRequestContext*> contexts;
1682 for (ContextGetterList::const_iterator getter = context_getters_.begin();
1683 getter != context_getters_.end(); ++getter) {
1684 contexts.insert((*getter)->GetURLRequestContext());
1686 contexts.insert(io_thread_->globals()->proxy_script_fetcher_context.get());
1687 contexts.insert(io_thread_->globals()->system_request_context.get());
1689 // Put together the list of all requests.
1690 std::vector<const net::URLRequest*> requests;
1691 for (std::set<net::URLRequestContext*>::const_iterator context =
1693 context != contexts.end(); ++context) {
1694 std::set<const net::URLRequest*>* context_requests =
1695 (*context)->url_requests();
1696 for (std::set<const net::URLRequest*>::const_iterator request_it =
1697 context_requests->begin();
1698 request_it != context_requests->end(); ++request_it) {
1699 DCHECK_EQ(io_thread_->net_log(), (*request_it)->net_log().net_log());
1700 requests.push_back(*request_it);
1704 // Sort by creation time.
1705 std::sort(requests.begin(), requests.end(), RequestCreatedBefore);
1707 // Create fake events.
1708 for (std::vector<const net::URLRequest*>::const_iterator request_it =
1710 request_it != requests.end(); ++request_it) {
1711 const net::URLRequest* request = *request_it;
1712 net::NetLog::ParametersCallback callback =
1713 base::Bind(&GetRequestStateAsValue, base::Unretained(request));
1715 // Create and add the entry directly, to avoid sending it to any other
1716 // NetLog observers.
1717 net::NetLog::EntryData entry_data(net::NetLog::TYPE_REQUEST_ALIVE,
1718 request->net_log().source(),
1719 net::NetLog::PHASE_BEGIN,
1720 request->creation_time(),
1722 net::NetLog::Entry entry(&entry_data, request->net_log().GetLogLevel());
1724 // Have to add |entry| to the queue synchronously, as there may already
1725 // be posted tasks queued up to add other events for |request|, which we
1726 // want |entry| to precede.
1727 AddEntryToQueue(entry.ToValue());
1734 ////////////////////////////////////////////////////////////////////////////////
1738 ////////////////////////////////////////////////////////////////////////////////
1741 base::Value* NetInternalsUI::GetConstants() {
1742 base::DictionaryValue* constants_dict = net::NetLogLogger::GetConstants();
1743 DCHECK(constants_dict);
1745 // Add a dictionary with the version of the client and its command line
1748 base::DictionaryValue* dict = new base::DictionaryValue();
1750 chrome::VersionInfo version_info;
1752 if (!version_info.is_valid()) {
1753 DLOG(ERROR) << "Unable to create chrome::VersionInfo";
1755 // We have everything we need to send the right values.
1756 dict->SetString("name", version_info.Name());
1757 dict->SetString("version", version_info.Version());
1758 dict->SetString("cl", version_info.LastChange());
1759 dict->SetString("version_mod",
1760 chrome::VersionInfo::GetVersionStringModifier());
1761 dict->SetString("official",
1762 version_info.IsOfficialBuild() ? "official" :
1764 dict->SetString("os_type", version_info.OSType());
1765 dict->SetString("command_line",
1766 CommandLine::ForCurrentProcess()->GetCommandLineString());
1769 constants_dict->Set("clientInfo", dict);
1772 return constants_dict;
1775 NetInternalsUI::NetInternalsUI(content::WebUI* web_ui)
1776 : WebUIController(web_ui) {
1777 web_ui->AddMessageHandler(new NetInternalsMessageHandler());
1779 // Set up the chrome://net-internals/ source.
1780 Profile* profile = Profile::FromWebUI(web_ui);
1781 content::WebUIDataSource::Add(profile, CreateNetInternalsHTMLSource());