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/files/file.h"
18 #include "base/files/file_path.h"
19 #include "base/files/file_util.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/values.h"
30 #include "chrome/browser/browser_process.h"
31 #include "chrome/browser/browsing_data/browsing_data_helper.h"
32 #include "chrome/browser/browsing_data/browsing_data_remover.h"
33 #include "chrome/browser/chrome_notification_types.h"
34 #include "chrome/browser/download/download_prefs.h"
35 #include "chrome/browser/io_thread.h"
36 #include "chrome/browser/net/chrome_network_delegate.h"
37 #include "chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.h"
38 #include "chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings_factory.h"
39 #include "chrome/browser/prerender/prerender_manager.h"
40 #include "chrome/browser/prerender/prerender_manager_factory.h"
41 #include "chrome/browser/profiles/profile.h"
42 #include "chrome/common/channel_info.h"
43 #include "chrome/common/chrome_paths.h"
44 #include "chrome/common/url_constants.h"
45 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h"
46 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h"
47 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h"
48 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_event_store.h"
49 #include "components/net_log/chrome_net_log.h"
50 #include "components/onc/onc_constants.h"
51 #include "components/url_formatter/url_fixer.h"
52 #include "components/version_info/version_info.h"
53 #include "content/public/browser/browser_thread.h"
54 #include "content/public/browser/notification_details.h"
55 #include "content/public/browser/resource_dispatcher_host.h"
56 #include "content/public/browser/web_contents.h"
57 #include "content/public/browser/web_ui.h"
58 #include "content/public/browser/web_ui_data_source.h"
59 #include "content/public/browser/web_ui_message_handler.h"
60 #include "grit/net_internals_resources.h"
61 #include "net/base/net_errors.h"
62 #include "net/base/net_util.h"
63 #include "net/disk_cache/disk_cache.h"
64 #include "net/dns/host_cache.h"
65 #include "net/dns/host_resolver.h"
66 #include "net/http/http_cache.h"
67 #include "net/http/http_network_layer.h"
68 #include "net/http/http_network_session.h"
69 #include "net/http/http_server_properties.h"
70 #include "net/http/http_stream_factory.h"
71 #include "net/http/transport_security_state.h"
72 #include "net/log/net_log_util.h"
73 #include "net/log/write_to_file_net_log_observer.h"
74 #include "net/proxy/proxy_service.h"
75 #include "net/url_request/url_request_context.h"
76 #include "net/url_request/url_request_context_getter.h"
78 #if defined(OS_CHROMEOS)
79 #include "chrome/browser/chromeos/file_manager/filesystem_api_util.h"
80 #include "chrome/browser/chromeos/net/onc_utils.h"
81 #include "chrome/browser/chromeos/profiles/profile_helper.h"
82 #include "chrome/browser/chromeos/system_logs/debug_log_writer.h"
83 #include "chrome/browser/net/nss_context.h"
84 #include "chromeos/dbus/dbus_thread_manager.h"
85 #include "chromeos/dbus/debug_daemon_client.h"
86 #include "chromeos/network/onc/onc_certificate_importer_impl.h"
87 #include "chromeos/network/onc/onc_utils.h"
88 #include "components/user_manager/user.h"
92 #include "chrome/browser/net/service_providers_win.h"
95 #if defined(ENABLE_EXTENSIONS)
96 #include "chrome/browser/extensions/extension_service.h"
97 #include "chrome/browser/ui/webui/extensions/extension_basic_info.h"
98 #include "extensions/browser/extension_registry.h"
99 #include "extensions/browser/extension_system.h"
100 #include "extensions/common/extension_set.h"
103 using base::StringValue
;
104 using content::BrowserThread
;
105 using content::WebContents
;
106 using content::WebUIMessageHandler
;
110 // Delay between when an event occurs and when it is passed to the Javascript
111 // page. All events that occur during this period are grouped together and
112 // sent to the page at once, which reduces context switching and CPU usage.
113 const int kNetLogEventDelayMilliseconds
= 100;
115 // Returns the HostCache for |context|'s primary HostResolver, or NULL if
117 net::HostCache
* GetHostResolverCache(net::URLRequestContext
* context
) {
118 return context
->host_resolver()->GetHostCache();
121 std::string
HashesToBase64String(const net::HashValueVector
& hashes
) {
123 for (size_t i
= 0; i
!= hashes
.size(); ++i
) {
126 str
+= hashes
[i
].ToString();
131 bool Base64StringToHashes(const std::string
& hashes_str
,
132 net::HashValueVector
* hashes
) {
134 std::vector
<std::string
> vector_hash_str
= base::SplitString(
135 hashes_str
, ",", base::TRIM_WHITESPACE
, base::SPLIT_WANT_ALL
);
137 for (size_t i
= 0; i
!= vector_hash_str
.size(); ++i
) {
138 std::string hash_str
;
139 base::RemoveChars(vector_hash_str
[i
], " \t\r\n", &hash_str
);
141 // Skip past unrecognized hash algos
142 // But return false on malformatted input
143 if (hash_str
.empty())
145 if (hash_str
.compare(0, 5, "sha1/") != 0 &&
146 hash_str
.compare(0, 7, "sha256/") != 0) {
149 if (!hash
.FromString(hash_str
))
151 hashes
->push_back(hash
);
156 // Returns the http network session for |context| if there is one.
157 // Otherwise, returns NULL.
158 net::HttpNetworkSession
* GetHttpNetworkSession(
159 net::URLRequestContext
* context
) {
160 if (!context
->http_transaction_factory())
163 return context
->http_transaction_factory()->GetSession();
166 content::WebUIDataSource
* CreateNetInternalsHTMLSource() {
167 content::WebUIDataSource
* source
=
168 content::WebUIDataSource::Create(chrome::kChromeUINetInternalsHost
);
170 source
->SetDefaultResource(IDR_NET_INTERNALS_INDEX_HTML
);
171 source
->AddResourcePath("index.js", IDR_NET_INTERNALS_INDEX_JS
);
172 source
->SetJsonPath("strings.js");
176 // This class receives javascript messages from the renderer.
177 // Note that the WebUI infrastructure runs on the UI thread, therefore all of
178 // this class's methods are expected to run on the UI thread.
180 // Since the network code we want to run lives on the IO thread, we proxy
181 // almost everything over to NetInternalsMessageHandler::IOThreadImpl, which
182 // runs on the IO thread.
184 // TODO(eroman): Can we start on the IO thread to begin with?
185 class NetInternalsMessageHandler
186 : public WebUIMessageHandler
,
187 public base::SupportsWeakPtr
<NetInternalsMessageHandler
> {
189 NetInternalsMessageHandler();
190 ~NetInternalsMessageHandler() override
;
192 // WebUIMessageHandler implementation.
193 void RegisterMessages() override
;
195 // Calls g_browser.receive in the renderer, passing in |command| and |arg|.
196 // Takes ownership of |arg|. If the renderer is displaying a log file, the
197 // message will be ignored.
198 void SendJavascriptCommand(const std::string
& command
, base::Value
* arg
);
200 // Javascript message handlers.
201 void OnRendererReady(const base::ListValue
* list
);
202 void OnClearBrowserCache(const base::ListValue
* list
);
203 void OnGetPrerenderInfo(const base::ListValue
* list
);
204 void OnGetHistoricNetworkStats(const base::ListValue
* list
);
205 void OnGetExtensionInfo(const base::ListValue
* list
);
206 void OnGetDataReductionProxyInfo(const base::ListValue
* list
);
207 #if defined(OS_CHROMEOS)
208 void OnImportONCFile(const base::ListValue
* list
);
209 void OnStoreDebugLogs(const base::ListValue
* list
);
210 void OnStoreDebugLogsCompleted(const base::FilePath
& log_path
,
212 void OnSetNetworkDebugMode(const base::ListValue
* list
);
213 void OnSetNetworkDebugModeCompleted(const std::string
& subsystem
,
216 // Callback to |GetNSSCertDatabaseForProfile| used to retrieve the database
217 // to which user's ONC defined certificates should be imported.
218 // It parses and imports |onc_blob|.
219 void ImportONCFileToNSSDB(const std::string
& onc_blob
,
220 const std::string
& passcode
,
221 net::NSSCertDatabase
* nssdb
);
223 // Called back by the CertificateImporter when a certificate import finished.
224 // |previous_error| contains earlier errors during this import.
225 void OnCertificatesImported(
226 const std::string
& previous_error
,
228 const net::CertificateList
& onc_trusted_certificates
);
234 // This is the "real" message handler, which lives on the IO thread.
235 scoped_refptr
<IOThreadImpl
> proxy_
;
237 base::WeakPtr
<prerender::PrerenderManager
> prerender_manager_
;
239 DISALLOW_COPY_AND_ASSIGN(NetInternalsMessageHandler
);
242 // This class is the "real" message handler. It is allocated and destroyed on
243 // the UI thread. With the exception of OnAddEntry, OnWebUIDeleted, and
244 // SendJavascriptCommand, its methods are all expected to be called from the IO
245 // thread. OnAddEntry and SendJavascriptCommand can be called from any thread,
246 // and OnWebUIDeleted can only be called from the UI thread.
247 class NetInternalsMessageHandler::IOThreadImpl
248 : public base::RefCountedThreadSafe
<
249 NetInternalsMessageHandler::IOThreadImpl
,
250 BrowserThread::DeleteOnUIThread
>,
251 public net::NetLog::ThreadSafeObserver
{
253 // Type for methods that can be used as MessageHandler callbacks.
254 typedef void (IOThreadImpl::*MessageHandler
)(const base::ListValue
*);
256 // Creates a proxy for |handler| that will live on the IO thread.
257 // |handler| is a weak pointer, since it is possible for the
258 // WebUIMessageHandler to be deleted on the UI thread while we were executing
259 // on the IO thread. |io_thread| is the global IOThread (it is passed in as
260 // an argument since we need to grab it from the UI thread).
262 const base::WeakPtr
<NetInternalsMessageHandler
>& handler
,
264 net::URLRequestContextGetter
* main_context_getter
);
266 // Called on UI thread just after creation, to add a ContextGetter to
267 // |context_getters_|.
268 void AddRequestContextGetter(net::URLRequestContextGetter
* context_getter
);
270 // Helper method to enable a callback that will be executed on the IO thread.
271 static void CallbackHelper(MessageHandler method
,
272 scoped_refptr
<IOThreadImpl
> io_thread
,
273 const base::ListValue
* list
);
275 // Called once the WebUI has been deleted (i.e. renderer went away), on the
279 // Called when the WebUI is deleted. Prevents calling Javascript functions
280 // afterwards. Called on UI thread.
281 void OnWebUIDeleted();
283 //--------------------------------
284 // Javascript message handlers:
285 //--------------------------------
287 void OnRendererReady(const base::ListValue
* list
);
289 void OnGetNetInfo(const base::ListValue
* list
);
290 void OnReloadProxySettings(const base::ListValue
* list
);
291 void OnClearBadProxies(const base::ListValue
* list
);
292 void OnClearHostResolverCache(const base::ListValue
* list
);
293 void OnHSTSQuery(const base::ListValue
* list
);
294 void OnHSTSAdd(const base::ListValue
* list
);
295 void OnHSTSDelete(const base::ListValue
* list
);
296 void OnGetSessionNetworkStats(const base::ListValue
* list
);
297 void OnCloseIdleSockets(const base::ListValue
* list
);
298 void OnFlushSocketPools(const base::ListValue
* list
);
300 void OnGetServiceProviders(const base::ListValue
* list
);
302 void OnSetCaptureMode(const base::ListValue
* list
);
304 // NetLog::ThreadSafeObserver implementation:
305 void OnAddEntry(const net::NetLog::Entry
& entry
) override
;
307 // Helper that calls g_browser.receive in the renderer, passing in |command|
308 // and |arg|. Takes ownership of |arg|. If the renderer is displaying a log
309 // file, the message will be ignored. Note that this can be called from any
311 void SendJavascriptCommand(const std::string
& command
, base::Value
* arg
);
314 friend struct BrowserThread::DeleteOnThread
<BrowserThread::UI
>;
315 friend class base::DeleteHelper
<IOThreadImpl
>;
317 typedef std::list
<scoped_refptr
<net::URLRequestContextGetter
> >
320 ~IOThreadImpl() override
;
322 // Adds |entry| to the queue of pending log entries to be sent to the page via
323 // Javascript. Must be called on the IO Thread. Also creates a delayed task
324 // that will call PostPendingEntries, if there isn't one already.
325 void AddEntryToQueue(base::Value
* entry
);
327 // Sends all pending entries to the page via Javascript, and clears the list
328 // of pending entries. Sending multiple entries at once results in a
329 // significant reduction of CPU usage when a lot of events are happening.
330 // Must be called on the IO Thread.
331 void PostPendingEntries();
333 // Adds entries with the states of ongoing URL requests.
334 void PrePopulateEventList();
336 net::URLRequestContext
* GetMainContext() {
337 return main_context_getter_
->GetURLRequestContext();
340 // |info_sources| is an or'd together list of the net::NetInfoSources to
341 // send information about. Information is sent to Javascript in the form of
342 // a single dictionary with information about all requests sources.
343 void SendNetInfo(int info_sources
);
345 // Pointer to the UI-thread message handler. Only access this from
347 base::WeakPtr
<NetInternalsMessageHandler
> handler_
;
349 // The global IOThread, which contains the global NetLog to observer.
350 IOThread
* io_thread_
;
352 // The main URLRequestContextGetter for the tab's profile.
353 scoped_refptr
<net::URLRequestContextGetter
> main_context_getter_
;
355 // True if the Web UI has been deleted. This is used to prevent calling
356 // Javascript functions after the Web UI is destroyed. On refresh, the
357 // messages can end up being sent to the refreshed page, causing duplicate
358 // or partial entries.
360 // This is only read and written to on the UI thread.
361 bool was_webui_deleted_
;
363 // Log entries that have yet to be passed along to Javascript page. Non-NULL
364 // when and only when there is a pending delayed task to call
365 // PostPendingEntries. Read and written to exclusively on the IO Thread.
366 scoped_ptr
<base::ListValue
> pending_entries_
;
368 // Used for getting current status of URLRequests when net-internals is
369 // opened. |main_context_getter_| is automatically added on construction.
370 // Duplicates are allowed.
371 ContextGetterList context_getters_
;
373 DISALLOW_COPY_AND_ASSIGN(IOThreadImpl
);
376 ////////////////////////////////////////////////////////////////////////////////
378 // NetInternalsMessageHandler
380 ////////////////////////////////////////////////////////////////////////////////
382 NetInternalsMessageHandler::NetInternalsMessageHandler() {}
384 NetInternalsMessageHandler::~NetInternalsMessageHandler() {
386 proxy_
.get()->OnWebUIDeleted();
387 // Notify the handler on the IO thread that the renderer is gone.
388 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
389 base::Bind(&IOThreadImpl::Detach
, proxy_
.get()));
393 void NetInternalsMessageHandler::RegisterMessages() {
394 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
396 Profile
* profile
= Profile::FromWebUI(web_ui());
398 proxy_
= new IOThreadImpl(this->AsWeakPtr(), g_browser_process
->io_thread(),
399 profile
->GetRequestContext());
400 proxy_
->AddRequestContextGetter(profile
->GetMediaRequestContext());
401 #if defined(ENABLE_EXTENSIONS)
402 proxy_
->AddRequestContextGetter(profile
->GetRequestContextForExtensions());
405 prerender::PrerenderManager
* prerender_manager
=
406 prerender::PrerenderManagerFactory::GetForProfile(profile
);
407 if (prerender_manager
) {
408 prerender_manager_
= prerender_manager
->AsWeakPtr();
410 prerender_manager_
= base::WeakPtr
<prerender::PrerenderManager
>();
413 web_ui()->RegisterMessageCallback(
415 base::Bind(&NetInternalsMessageHandler::OnRendererReady
,
416 base::Unretained(this)));
417 web_ui()->RegisterMessageCallback(
419 base::Bind(&IOThreadImpl::CallbackHelper
,
420 &IOThreadImpl::OnGetNetInfo
, proxy_
));
421 web_ui()->RegisterMessageCallback(
422 "reloadProxySettings",
423 base::Bind(&IOThreadImpl::CallbackHelper
,
424 &IOThreadImpl::OnReloadProxySettings
, proxy_
));
425 web_ui()->RegisterMessageCallback(
427 base::Bind(&IOThreadImpl::CallbackHelper
,
428 &IOThreadImpl::OnClearBadProxies
, proxy_
));
429 web_ui()->RegisterMessageCallback(
430 "clearHostResolverCache",
431 base::Bind(&IOThreadImpl::CallbackHelper
,
432 &IOThreadImpl::OnClearHostResolverCache
, proxy_
));
433 web_ui()->RegisterMessageCallback(
435 base::Bind(&IOThreadImpl::CallbackHelper
,
436 &IOThreadImpl::OnHSTSQuery
, proxy_
));
437 web_ui()->RegisterMessageCallback(
439 base::Bind(&IOThreadImpl::CallbackHelper
,
440 &IOThreadImpl::OnHSTSAdd
, proxy_
));
441 web_ui()->RegisterMessageCallback(
443 base::Bind(&IOThreadImpl::CallbackHelper
,
444 &IOThreadImpl::OnHSTSDelete
, proxy_
));
445 web_ui()->RegisterMessageCallback(
446 "getSessionNetworkStats",
447 base::Bind(&IOThreadImpl::CallbackHelper
,
448 &IOThreadImpl::OnGetSessionNetworkStats
, proxy_
));
449 web_ui()->RegisterMessageCallback(
451 base::Bind(&IOThreadImpl::CallbackHelper
,
452 &IOThreadImpl::OnCloseIdleSockets
, proxy_
));
453 web_ui()->RegisterMessageCallback(
455 base::Bind(&IOThreadImpl::CallbackHelper
,
456 &IOThreadImpl::OnFlushSocketPools
, proxy_
));
458 web_ui()->RegisterMessageCallback(
459 "getServiceProviders",
460 base::Bind(&IOThreadImpl::CallbackHelper
,
461 &IOThreadImpl::OnGetServiceProviders
, proxy_
));
464 web_ui()->RegisterMessageCallback(
465 "setCaptureMode", base::Bind(&IOThreadImpl::CallbackHelper
,
466 &IOThreadImpl::OnSetCaptureMode
, proxy_
));
467 web_ui()->RegisterMessageCallback(
469 base::Bind(&NetInternalsMessageHandler::OnClearBrowserCache
,
470 base::Unretained(this)));
471 web_ui()->RegisterMessageCallback(
473 base::Bind(&NetInternalsMessageHandler::OnGetPrerenderInfo
,
474 base::Unretained(this)));
475 web_ui()->RegisterMessageCallback(
476 "getHistoricNetworkStats",
477 base::Bind(&NetInternalsMessageHandler::OnGetHistoricNetworkStats
,
478 base::Unretained(this)));
479 web_ui()->RegisterMessageCallback(
481 base::Bind(&NetInternalsMessageHandler::OnGetExtensionInfo
,
482 base::Unretained(this)));
483 web_ui()->RegisterMessageCallback(
484 "getDataReductionProxyInfo",
485 base::Bind(&NetInternalsMessageHandler::OnGetDataReductionProxyInfo
,
486 base::Unretained(this)));
487 #if defined(OS_CHROMEOS)
488 web_ui()->RegisterMessageCallback(
490 base::Bind(&NetInternalsMessageHandler::OnImportONCFile
,
491 base::Unretained(this)));
492 web_ui()->RegisterMessageCallback(
494 base::Bind(&NetInternalsMessageHandler::OnStoreDebugLogs
,
495 base::Unretained(this)));
496 web_ui()->RegisterMessageCallback(
497 "setNetworkDebugMode",
498 base::Bind(&NetInternalsMessageHandler::OnSetNetworkDebugMode
,
499 base::Unretained(this)));
503 void NetInternalsMessageHandler::SendJavascriptCommand(
504 const std::string
& command
,
506 scoped_ptr
<base::Value
> command_value(new base::StringValue(command
));
507 scoped_ptr
<base::Value
> value(arg
);
508 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
510 web_ui()->CallJavascriptFunction("g_browser.receive",
511 *command_value
.get(),
514 web_ui()->CallJavascriptFunction("g_browser.receive",
515 *command_value
.get());
519 void NetInternalsMessageHandler::OnRendererReady(const base::ListValue
* list
) {
520 IOThreadImpl::CallbackHelper(&IOThreadImpl::OnRendererReady
, proxy_
, list
);
523 void NetInternalsMessageHandler::OnClearBrowserCache(
524 const base::ListValue
* list
) {
525 BrowsingDataRemover
* remover
= BrowsingDataRemover::CreateForUnboundedRange(
526 Profile::FromWebUI(web_ui()));
527 remover
->Remove(BrowsingDataRemover::REMOVE_CACHE
,
528 BrowsingDataHelper::UNPROTECTED_WEB
);
529 // BrowsingDataRemover deletes itself.
532 void NetInternalsMessageHandler::OnGetPrerenderInfo(
533 const base::ListValue
* list
) {
534 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
536 base::DictionaryValue
* value
= NULL
;
537 prerender::PrerenderManager
* prerender_manager
= prerender_manager_
.get();
538 if (!prerender_manager
) {
539 value
= new base::DictionaryValue();
540 value
->SetBoolean("enabled", false);
541 value
->SetBoolean("omnibox_enabled", false);
543 value
= prerender_manager
->GetAsValue();
545 SendJavascriptCommand("receivedPrerenderInfo", value
);
548 void NetInternalsMessageHandler::OnGetHistoricNetworkStats(
549 const base::ListValue
* list
) {
550 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
551 base::Value
* historic_network_info
= NULL
;
552 Profile
* profile
= Profile::FromWebUI(web_ui());
553 DataReductionProxyChromeSettings
* data_reduction_proxy_settings
=
554 DataReductionProxyChromeSettingsFactory::GetForBrowserContext(profile
);
555 if (data_reduction_proxy_settings
) {
556 data_reduction_proxy::DataReductionProxyCompressionStats
*
558 data_reduction_proxy_settings
->data_reduction_proxy_service()
559 ->compression_stats();
560 historic_network_info
=
561 compression_stats
->HistoricNetworkStatsInfoToValue();
563 SendJavascriptCommand("receivedHistoricNetworkStats", historic_network_info
);
566 void NetInternalsMessageHandler::OnGetExtensionInfo(
567 const base::ListValue
* list
) {
568 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
569 base::ListValue
* extension_list
= new base::ListValue();
570 #if defined(ENABLE_EXTENSIONS)
571 Profile
* profile
= Profile::FromWebUI(web_ui());
572 extensions::ExtensionSystem
* extension_system
=
573 extensions::ExtensionSystem::Get(profile
);
574 if (extension_system
) {
575 ExtensionService
* extension_service
= extension_system
->extension_service();
576 if (extension_service
) {
577 scoped_ptr
<const extensions::ExtensionSet
> extensions(
578 extensions::ExtensionRegistry::Get(profile
)
579 ->GenerateInstalledExtensionsSet());
580 for (extensions::ExtensionSet::const_iterator it
= extensions
->begin();
581 it
!= extensions
->end(); ++it
) {
582 base::DictionaryValue
* extension_info
= new base::DictionaryValue();
583 bool enabled
= extension_service
->IsExtensionEnabled((*it
)->id());
584 extensions::GetExtensionBasicInfo(it
->get(), enabled
, extension_info
);
585 extension_list
->Append(extension_info
);
590 SendJavascriptCommand("receivedExtensionInfo", extension_list
);
593 void NetInternalsMessageHandler::OnGetDataReductionProxyInfo(
594 const base::ListValue
* list
) {
595 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
596 Profile
* profile
= Profile::FromWebUI(web_ui());
597 DataReductionProxyChromeSettings
* data_reduction_proxy_settings
=
598 DataReductionProxyChromeSettingsFactory::GetForBrowserContext(profile
);
599 data_reduction_proxy::DataReductionProxyEventStore
* event_store
=
600 (data_reduction_proxy_settings
== nullptr) ? nullptr :
601 data_reduction_proxy_settings
->GetEventStore();
602 SendJavascriptCommand(
603 "receivedDataReductionProxyInfo",
604 (event_store
== nullptr) ? nullptr : event_store
->GetSummaryValue());
607 ////////////////////////////////////////////////////////////////////////////////
609 // NetInternalsMessageHandler::IOThreadImpl
611 ////////////////////////////////////////////////////////////////////////////////
613 NetInternalsMessageHandler::IOThreadImpl::IOThreadImpl(
614 const base::WeakPtr
<NetInternalsMessageHandler
>& handler
,
616 net::URLRequestContextGetter
* main_context_getter
)
618 io_thread_(io_thread
),
619 main_context_getter_(main_context_getter
),
620 was_webui_deleted_(false) {
621 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
622 AddRequestContextGetter(main_context_getter
);
625 NetInternalsMessageHandler::IOThreadImpl::~IOThreadImpl() {
626 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
629 void NetInternalsMessageHandler::IOThreadImpl::AddRequestContextGetter(
630 net::URLRequestContextGetter
* context_getter
) {
631 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
632 context_getters_
.push_back(context_getter
);
635 void NetInternalsMessageHandler::IOThreadImpl::CallbackHelper(
636 MessageHandler method
,
637 scoped_refptr
<IOThreadImpl
> io_thread
,
638 const base::ListValue
* list
) {
639 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
641 // We need to make a copy of the value in order to pass it over to the IO
642 // thread. |list_copy| will be deleted when the task is destroyed. The called
643 // |method| cannot take ownership of |list_copy|.
644 base::ListValue
* list_copy
=
645 (list
&& list
->GetSize()) ? list
->DeepCopy() : NULL
;
647 BrowserThread::PostTask(
648 BrowserThread::IO
, FROM_HERE
,
649 base::Bind(method
, io_thread
, base::Owned(list_copy
)));
652 void NetInternalsMessageHandler::IOThreadImpl::Detach() {
653 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
654 // Unregister with network stack to observe events.
656 net_log()->DeprecatedRemoveObserver(this);
659 void NetInternalsMessageHandler::IOThreadImpl::OnWebUIDeleted() {
660 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
661 was_webui_deleted_
= true;
664 void NetInternalsMessageHandler::IOThreadImpl::OnRendererReady(
665 const base::ListValue
* list
) {
666 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
668 // If currently watching the NetLog, temporarily stop watching it and flush
669 // pending events, so they won't appear before the status events created for
670 // currently active network objects below.
672 net_log()->DeprecatedRemoveObserver(this);
673 PostPendingEntries();
676 SendJavascriptCommand(
678 net_log::ChromeNetLog::GetConstants(
679 base::CommandLine::ForCurrentProcess()->GetCommandLineString(),
680 chrome::GetChannelString()));
682 PrePopulateEventList();
684 // Register with network stack to observe events.
685 io_thread_
->net_log()->DeprecatedAddObserver(
686 this, net::NetLogCaptureMode::IncludeCookiesAndCredentials());
689 void NetInternalsMessageHandler::IOThreadImpl::OnGetNetInfo(
690 const base::ListValue
* list
) {
693 if (!list
->GetInteger(0, &info_sources
))
695 SendNetInfo(info_sources
);
698 void NetInternalsMessageHandler::IOThreadImpl::OnReloadProxySettings(
699 const base::ListValue
* list
) {
701 GetMainContext()->proxy_service()->ForceReloadProxyConfig();
703 // Cause the renderer to be notified of the new values.
704 SendNetInfo(net::NET_INFO_PROXY_SETTINGS
);
707 void NetInternalsMessageHandler::IOThreadImpl::OnClearBadProxies(
708 const base::ListValue
* list
) {
710 GetMainContext()->proxy_service()->ClearBadProxiesCache();
712 // Cause the renderer to be notified of the new values.
713 SendNetInfo(net::NET_INFO_BAD_PROXIES
);
716 void NetInternalsMessageHandler::IOThreadImpl::OnClearHostResolverCache(
717 const base::ListValue
* list
) {
719 net::HostCache
* cache
= GetHostResolverCache(GetMainContext());
724 // Cause the renderer to be notified of the new values.
725 SendNetInfo(net::NET_INFO_HOST_RESOLVER
);
728 void NetInternalsMessageHandler::IOThreadImpl::OnHSTSQuery(
729 const base::ListValue
* list
) {
730 // |list| should be: [<domain to query>].
732 CHECK(list
->GetString(0, &domain
));
733 base::DictionaryValue
* result
= new base::DictionaryValue();
735 if (!base::IsStringASCII(domain
)) {
736 result
->SetString("error", "non-ASCII domain name");
738 net::TransportSecurityState
* transport_security_state
=
739 GetMainContext()->transport_security_state();
740 if (!transport_security_state
) {
741 result
->SetString("error", "no TransportSecurityState active");
743 net::TransportSecurityState::STSState static_sts_state
;
744 net::TransportSecurityState::PKPState static_pkp_state
;
745 const bool found_static
= transport_security_state
->GetStaticDomainState(
746 domain
, &static_sts_state
, &static_pkp_state
);
748 result
->SetInteger("static_upgrade_mode",
749 static_cast<int>(static_sts_state
.upgrade_mode
));
750 result
->SetBoolean("static_sts_include_subdomains",
751 static_sts_state
.include_subdomains
);
752 result
->SetDouble("static_sts_observed",
753 static_sts_state
.last_observed
.ToDoubleT());
754 result
->SetDouble("static_sts_expiry",
755 static_sts_state
.expiry
.ToDoubleT());
756 result
->SetBoolean("static_pkp_include_subdomains",
757 static_pkp_state
.include_subdomains
);
758 result
->SetDouble("static_pkp_observed",
759 static_pkp_state
.last_observed
.ToDoubleT());
760 result
->SetDouble("static_pkp_expiry",
761 static_pkp_state
.expiry
.ToDoubleT());
762 result
->SetString("static_spki_hashes",
763 HashesToBase64String(static_pkp_state
.spki_hashes
));
764 result
->SetString("static_sts_domain", static_sts_state
.domain
);
765 result
->SetString("static_pkp_domain", static_pkp_state
.domain
);
768 net::TransportSecurityState::STSState dynamic_sts_state
;
769 net::TransportSecurityState::PKPState dynamic_pkp_state
;
770 const bool found_sts_dynamic
=
771 transport_security_state
->GetDynamicSTSState(domain
,
774 const bool found_pkp_dynamic
=
775 transport_security_state
->GetDynamicPKPState(domain
,
777 if (found_sts_dynamic
) {
778 result
->SetInteger("dynamic_upgrade_mode",
779 static_cast<int>(dynamic_sts_state
.upgrade_mode
));
780 result
->SetBoolean("dynamic_sts_include_subdomains",
781 dynamic_sts_state
.include_subdomains
);
782 result
->SetDouble("dynamic_sts_observed",
783 dynamic_sts_state
.last_observed
.ToDoubleT());
784 result
->SetDouble("dynamic_sts_expiry",
785 dynamic_sts_state
.expiry
.ToDoubleT());
786 result
->SetString("dynamic_sts_domain", dynamic_sts_state
.domain
);
789 if (found_pkp_dynamic
) {
790 result
->SetBoolean("dynamic_pkp_include_subdomains",
791 dynamic_pkp_state
.include_subdomains
);
792 result
->SetDouble("dynamic_pkp_observed",
793 dynamic_pkp_state
.last_observed
.ToDoubleT());
794 result
->SetDouble("dynamic_pkp_expiry",
795 dynamic_pkp_state
.expiry
.ToDoubleT());
796 result
->SetString("dynamic_spki_hashes",
797 HashesToBase64String(dynamic_pkp_state
.spki_hashes
));
798 result
->SetString("dynamic_pkp_domain", dynamic_pkp_state
.domain
);
802 "result", found_static
|| found_sts_dynamic
|| found_pkp_dynamic
);
806 SendJavascriptCommand("receivedHSTSResult", result
);
809 void NetInternalsMessageHandler::IOThreadImpl::OnHSTSAdd(
810 const base::ListValue
* list
) {
811 // |list| should be: [<domain to query>, <STS include subdomains>, <PKP
812 // include subdomains>, <key pins>].
814 CHECK(list
->GetString(0, &domain
));
815 if (!base::IsStringASCII(domain
)) {
816 // Silently fail. The user will get a helpful error if they query for the
820 bool sts_include_subdomains
;
821 CHECK(list
->GetBoolean(1, &sts_include_subdomains
));
822 bool pkp_include_subdomains
;
823 CHECK(list
->GetBoolean(2, &pkp_include_subdomains
));
824 std::string hashes_str
;
825 CHECK(list
->GetString(3, &hashes_str
));
827 net::TransportSecurityState
* transport_security_state
=
828 GetMainContext()->transport_security_state();
829 if (!transport_security_state
)
832 base::Time expiry
= base::Time::Now() + base::TimeDelta::FromDays(1000);
833 net::HashValueVector hashes
;
834 if (!hashes_str
.empty()) {
835 if (!Base64StringToHashes(hashes_str
, &hashes
))
839 transport_security_state
->AddHSTS(domain
, expiry
, sts_include_subdomains
);
840 transport_security_state
->AddHPKP(domain
, expiry
, pkp_include_subdomains
,
844 void NetInternalsMessageHandler::IOThreadImpl::OnHSTSDelete(
845 const base::ListValue
* list
) {
846 // |list| should be: [<domain to query>].
848 CHECK(list
->GetString(0, &domain
));
849 if (!base::IsStringASCII(domain
)) {
850 // There cannot be a unicode entry in the HSTS set.
853 net::TransportSecurityState
* transport_security_state
=
854 GetMainContext()->transport_security_state();
855 if (!transport_security_state
)
858 transport_security_state
->DeleteDynamicDataForHost(domain
);
861 void NetInternalsMessageHandler::IOThreadImpl::OnGetSessionNetworkStats(
862 const base::ListValue
* list
) {
864 net::HttpNetworkSession
* http_network_session
=
865 GetHttpNetworkSession(main_context_getter_
->GetURLRequestContext());
867 base::Value
* network_info
= NULL
;
868 if (http_network_session
) {
869 data_reduction_proxy::DataReductionProxyNetworkDelegate
* net_delegate
=
870 static_cast<data_reduction_proxy::DataReductionProxyNetworkDelegate
*>(
871 http_network_session
->network_delegate());
873 network_info
= net_delegate
->SessionNetworkStatsInfoToValue();
876 SendJavascriptCommand("receivedSessionNetworkStats", network_info
);
879 void NetInternalsMessageHandler::IOThreadImpl::OnFlushSocketPools(
880 const base::ListValue
* list
) {
882 net::HttpNetworkSession
* http_network_session
=
883 GetHttpNetworkSession(GetMainContext());
885 if (http_network_session
)
886 http_network_session
->CloseAllConnections();
889 void NetInternalsMessageHandler::IOThreadImpl::OnCloseIdleSockets(
890 const base::ListValue
* list
) {
892 net::HttpNetworkSession
* http_network_session
=
893 GetHttpNetworkSession(GetMainContext());
895 if (http_network_session
)
896 http_network_session
->CloseIdleConnections();
900 void NetInternalsMessageHandler::IOThreadImpl::OnGetServiceProviders(
901 const base::ListValue
* list
) {
904 base::DictionaryValue
* service_providers
= new base::DictionaryValue();
906 WinsockLayeredServiceProviderList layered_providers
;
907 GetWinsockLayeredServiceProviders(&layered_providers
);
908 base::ListValue
* layered_provider_list
= new base::ListValue();
909 for (size_t i
= 0; i
< layered_providers
.size(); ++i
) {
910 base::DictionaryValue
* service_dict
= new base::DictionaryValue();
911 service_dict
->SetString("name", layered_providers
[i
].name
);
912 service_dict
->SetInteger("version", layered_providers
[i
].version
);
913 service_dict
->SetInteger("chain_length", layered_providers
[i
].chain_length
);
914 service_dict
->SetInteger("socket_type", layered_providers
[i
].socket_type
);
915 service_dict
->SetInteger("socket_protocol",
916 layered_providers
[i
].socket_protocol
);
917 service_dict
->SetString("path", layered_providers
[i
].path
);
919 layered_provider_list
->Append(service_dict
);
921 service_providers
->Set("service_providers", layered_provider_list
);
923 WinsockNamespaceProviderList namespace_providers
;
924 GetWinsockNamespaceProviders(&namespace_providers
);
925 base::ListValue
* namespace_list
= new base::ListValue
;
926 for (size_t i
= 0; i
< namespace_providers
.size(); ++i
) {
927 base::DictionaryValue
* namespace_dict
= new base::DictionaryValue();
928 namespace_dict
->SetString("name", namespace_providers
[i
].name
);
929 namespace_dict
->SetBoolean("active", namespace_providers
[i
].active
);
930 namespace_dict
->SetInteger("version", namespace_providers
[i
].version
);
931 namespace_dict
->SetInteger("type", namespace_providers
[i
].type
);
933 namespace_list
->Append(namespace_dict
);
935 service_providers
->Set("namespace_providers", namespace_list
);
937 SendJavascriptCommand("receivedServiceProviders", service_providers
);
941 #if defined(OS_CHROMEOS)
942 void NetInternalsMessageHandler::ImportONCFileToNSSDB(
943 const std::string
& onc_blob
,
944 const std::string
& passcode
,
945 net::NSSCertDatabase
* nssdb
) {
946 const user_manager::User
* user
=
947 chromeos::ProfileHelper::Get()->GetUserByProfile(
948 Profile::FromWebUI(web_ui()));
951 std::string error
= "User not found.";
952 SendJavascriptCommand("receivedONCFileParse", new base::StringValue(error
));
957 onc::ONCSource onc_source
= onc::ONC_SOURCE_USER_IMPORT
;
958 base::ListValue network_configs
;
959 base::DictionaryValue global_network_config
;
960 base::ListValue certificates
;
961 if (!chromeos::onc::ParseAndValidateOncForImport(onc_blob
,
965 &global_network_config
,
967 error
= "Errors occurred during the ONC parsing. ";
970 std::string network_error
;
971 chromeos::onc::ImportNetworksForUser(user
, network_configs
, &network_error
);
972 if (!network_error
.empty())
973 error
+= network_error
;
975 chromeos::onc::CertificateImporterImpl
cert_importer(
976 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO
), nssdb
);
977 cert_importer
.ImportCertificates(
980 base::Bind(&NetInternalsMessageHandler::OnCertificatesImported
,
985 void NetInternalsMessageHandler::OnCertificatesImported(
986 const std::string
& previous_error
,
988 const net::CertificateList
& /* unused onc_trusted_certificates */) {
989 std::string error
= previous_error
;
991 error
+= "Some certificates couldn't be imported. ";
993 SendJavascriptCommand("receivedONCFileParse", new base::StringValue(error
));
996 void NetInternalsMessageHandler::OnImportONCFile(
997 const base::ListValue
* list
) {
998 std::string onc_blob
;
999 std::string passcode
;
1000 if (list
->GetSize() != 2 ||
1001 !list
->GetString(0, &onc_blob
) ||
1002 !list
->GetString(1, &passcode
)) {
1006 GetNSSCertDatabaseForProfile(
1007 Profile::FromWebUI(web_ui()),
1008 base::Bind(&NetInternalsMessageHandler::ImportONCFileToNSSDB
, AsWeakPtr(),
1009 onc_blob
, passcode
));
1012 void NetInternalsMessageHandler::OnStoreDebugLogs(const base::ListValue
* list
) {
1015 SendJavascriptCommand("receivedStoreDebugLogs",
1016 new base::StringValue("Creating log file..."));
1017 Profile
* profile
= Profile::FromWebUI(web_ui());
1018 const DownloadPrefs
* const prefs
= DownloadPrefs::FromBrowserContext(profile
);
1019 base::FilePath path
= prefs
->DownloadPath();
1020 if (file_manager::util::IsUnderNonNativeLocalPath(profile
, path
))
1021 path
= prefs
->GetDefaultDownloadDirectoryForProfile();
1022 chromeos::DebugLogWriter::StoreLogs(
1024 true, // should_compress
1025 base::Bind(&NetInternalsMessageHandler::OnStoreDebugLogsCompleted
,
1029 void NetInternalsMessageHandler::OnStoreDebugLogsCompleted(
1030 const base::FilePath
& log_path
, bool succeeded
) {
1033 status
= "Created log file: " + log_path
.BaseName().AsUTF8Unsafe();
1035 status
= "Failed to create log file";
1036 SendJavascriptCommand("receivedStoreDebugLogs",
1037 new base::StringValue(status
));
1040 void NetInternalsMessageHandler::OnSetNetworkDebugMode(
1041 const base::ListValue
* list
) {
1042 std::string subsystem
;
1043 if (list
->GetSize() != 1 || !list
->GetString(0, &subsystem
))
1045 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->
1049 &NetInternalsMessageHandler::OnSetNetworkDebugModeCompleted
,
1054 void NetInternalsMessageHandler::OnSetNetworkDebugModeCompleted(
1055 const std::string
& subsystem
,
1059 status
= "Debug mode is changed to " + subsystem
;
1061 status
= "Failed to change debug mode to " + subsystem
;
1062 SendJavascriptCommand("receivedSetNetworkDebugMode",
1063 new base::StringValue(status
));
1065 #endif // defined(OS_CHROMEOS)
1067 void NetInternalsMessageHandler::IOThreadImpl::OnSetCaptureMode(
1068 const base::ListValue
* list
) {
1069 std::string capture_mode_string
;
1070 if (!list
->GetString(0, &capture_mode_string
)) {
1075 // Convert the string to a NetLogCaptureMode.
1076 net::NetLogCaptureMode mode
;
1077 if (capture_mode_string
== "IncludeSocketBytes") {
1078 mode
= net::NetLogCaptureMode::IncludeSocketBytes();
1079 } else if (capture_mode_string
== "IncludeCookiesAndCredentials") {
1080 mode
= net::NetLogCaptureMode::IncludeCookiesAndCredentials();
1085 net_log()->SetObserverCaptureMode(this, mode
);
1088 // Note that unlike other methods of IOThreadImpl, this function
1089 // can be called from ANY THREAD.
1090 void NetInternalsMessageHandler::IOThreadImpl::OnAddEntry(
1091 const net::NetLog::Entry
& entry
) {
1092 BrowserThread::PostTask(
1093 BrowserThread::IO
, FROM_HERE
,
1094 base::Bind(&IOThreadImpl::AddEntryToQueue
, this, entry
.ToValue()));
1097 // Note that this can be called from ANY THREAD.
1098 void NetInternalsMessageHandler::IOThreadImpl::SendJavascriptCommand(
1099 const std::string
& command
,
1101 if (BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
1102 if (handler_
.get() && !was_webui_deleted_
) {
1103 // We check |handler_| in case it was deleted on the UI thread earlier
1104 // while we were running on the IO thread.
1105 handler_
->SendJavascriptCommand(command
, arg
);
1112 if (!BrowserThread::PostTask(
1113 BrowserThread::UI
, FROM_HERE
,
1114 base::Bind(&IOThreadImpl::SendJavascriptCommand
, this, command
, arg
))) {
1115 // Failed posting the task, avoid leaking.
1120 void NetInternalsMessageHandler::IOThreadImpl::AddEntryToQueue(
1121 base::Value
* entry
) {
1122 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1123 if (!pending_entries_
.get()) {
1124 pending_entries_
.reset(new base::ListValue());
1125 BrowserThread::PostDelayedTask(
1126 BrowserThread::IO
, FROM_HERE
,
1127 base::Bind(&IOThreadImpl::PostPendingEntries
, this),
1128 base::TimeDelta::FromMilliseconds(kNetLogEventDelayMilliseconds
));
1130 pending_entries_
->Append(entry
);
1133 void NetInternalsMessageHandler::IOThreadImpl::PostPendingEntries() {
1134 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1135 if (pending_entries_
.get())
1136 SendJavascriptCommand("receivedLogEntries", pending_entries_
.release());
1139 void NetInternalsMessageHandler::IOThreadImpl::PrePopulateEventList() {
1140 // Using a set removes any duplicates.
1141 std::set
<net::URLRequestContext
*> contexts
;
1142 for (ContextGetterList::const_iterator getter
= context_getters_
.begin();
1143 getter
!= context_getters_
.end(); ++getter
) {
1144 contexts
.insert((*getter
)->GetURLRequestContext());
1146 contexts
.insert(io_thread_
->globals()->proxy_script_fetcher_context
.get());
1147 contexts
.insert(io_thread_
->globals()->system_request_context
.get());
1149 // Add entries for ongoing network objects.
1150 CreateNetLogEntriesForActiveObjects(contexts
, this);
1153 void NetInternalsMessageHandler::IOThreadImpl::SendNetInfo(int info_sources
) {
1154 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1155 SendJavascriptCommand(
1157 net::GetNetInfo(GetMainContext(), info_sources
).release());
1163 ////////////////////////////////////////////////////////////////////////////////
1167 ////////////////////////////////////////////////////////////////////////////////
1169 NetInternalsUI::NetInternalsUI(content::WebUI
* web_ui
)
1170 : WebUIController(web_ui
) {
1171 web_ui
->AddMessageHandler(new NetInternalsMessageHandler());
1173 // Set up the chrome://net-internals/ source.
1174 Profile
* profile
= Profile::FromWebUI(web_ui
);
1175 content::WebUIDataSource::Add(profile
, CreateNetInternalsHTMLSource());