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/threading/worker_pool.h"
31 #include "base/values.h"
32 #include "chrome/browser/browser_process.h"
33 #include "chrome/browser/browsing_data/browsing_data_helper.h"
34 #include "chrome/browser/browsing_data/browsing_data_remover.h"
35 #include "chrome/browser/chrome_notification_types.h"
36 #include "chrome/browser/download/download_prefs.h"
37 #include "chrome/browser/extensions/extension_service.h"
38 #include "chrome/browser/io_thread.h"
39 #include "chrome/browser/net/chrome_net_log.h"
40 #include "chrome/browser/net/chrome_network_delegate.h"
41 #include "chrome/browser/net/connection_tester.h"
42 #include "chrome/browser/prerender/prerender_manager.h"
43 #include "chrome/browser/prerender/prerender_manager_factory.h"
44 #include "chrome/browser/profiles/profile.h"
45 #include "chrome/browser/ui/webui/extensions/extension_basic_info.h"
46 #include "chrome/common/chrome_paths.h"
47 #include "chrome/common/chrome_version_info.h"
48 #include "chrome/common/logging_chrome.h"
49 #include "chrome/common/net/url_fixer_upper.h"
50 #include "chrome/common/pref_names.h"
51 #include "chrome/common/url_constants.h"
52 #include "components/onc/onc_constants.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 "extensions/browser/extension_registry.h"
61 #include "extensions/browser/extension_system.h"
62 #include "extensions/common/extension_set.h"
63 #include "grit/generated_resources.h"
64 #include "grit/net_internals_resources.h"
65 #include "net/base/net_errors.h"
66 #include "net/base/net_log_logger.h"
67 #include "net/base/net_util.h"
68 #include "net/disk_cache/disk_cache.h"
69 #include "net/dns/host_cache.h"
70 #include "net/dns/host_resolver.h"
71 #include "net/http/http_cache.h"
72 #include "net/http/http_network_layer.h"
73 #include "net/http/http_network_session.h"
74 #include "net/http/http_server_properties.h"
75 #include "net/http/http_stream_factory.h"
76 #include "net/http/transport_security_state.h"
77 #include "net/proxy/proxy_service.h"
78 #include "net/url_request/url_request_context.h"
79 #include "net/url_request/url_request_context_getter.h"
80 #include "ui/base/resource/resource_bundle.h"
82 #if defined(OS_CHROMEOS)
83 #include "chrome/browser/chromeos/login/user.h"
84 #include "chrome/browser/chromeos/login/user_manager.h"
85 #include "chrome/browser/chromeos/net/onc_utils.h"
86 #include "chrome/browser/chromeos/system/syslogs_provider.h"
87 #include "chrome/browser/net/nss_context.h"
88 #include "chromeos/dbus/dbus_thread_manager.h"
89 #include "chromeos/dbus/debug_daemon_client.h"
90 #include "chromeos/network/onc/onc_certificate_importer_impl.h"
91 #include "chromeos/network/onc/onc_utils.h"
94 #include "chrome/browser/net/service_providers_win.h"
97 using base::StringValue;
98 using content::BrowserThread;
99 using content::WebContents;
100 using content::WebUIMessageHandler;
104 // Delay between when an event occurs and when it is passed to the Javascript
105 // page. All events that occur during this period are grouped together and
106 // sent to the page at once, which reduces context switching and CPU usage.
107 const int kNetLogEventDelayMilliseconds = 100;
109 // Returns the HostCache for |context|'s primary HostResolver, or NULL if
111 net::HostCache* GetHostResolverCache(net::URLRequestContext* context) {
112 return context->host_resolver()->GetHostCache();
115 std::string HashesToBase64String(const net::HashValueVector& hashes) {
117 for (size_t i = 0; i != hashes.size(); ++i) {
120 str += hashes[i].ToString();
125 bool Base64StringToHashes(const std::string& hashes_str,
126 net::HashValueVector* hashes) {
128 std::vector<std::string> vector_hash_str;
129 base::SplitString(hashes_str, ',', &vector_hash_str);
131 for (size_t i = 0; i != vector_hash_str.size(); ++i) {
132 std::string hash_str;
133 base::RemoveChars(vector_hash_str[i], " \t\r\n", &hash_str);
135 // Skip past unrecognized hash algos
136 // But return false on malformatted input
137 if (hash_str.empty())
139 if (hash_str.compare(0, 5, "sha1/") != 0 &&
140 hash_str.compare(0, 7, "sha256/") != 0) {
143 if (!hash.FromString(hash_str))
145 hashes->push_back(hash);
150 // Returns a Value representing the state of a pre-existing URLRequest when
151 // net-internals was opened.
152 base::Value* GetRequestStateAsValue(const net::URLRequest* request,
153 net::NetLog::LogLevel log_level) {
154 return request->GetStateAsValue();
157 // Returns true if |request1| was created before |request2|.
158 bool RequestCreatedBefore(const net::URLRequest* request1,
159 const net::URLRequest* request2) {
160 return request1->creation_time() < request2->creation_time();
163 // Returns the disk cache backend for |context| if there is one, or NULL.
164 disk_cache::Backend* GetDiskCacheBackend(net::URLRequestContext* context) {
165 if (!context->http_transaction_factory())
168 net::HttpCache* http_cache = context->http_transaction_factory()->GetCache();
172 return http_cache->GetCurrentBackend();
175 // Returns the http network session for |context| if there is one.
176 // Otherwise, returns NULL.
177 net::HttpNetworkSession* GetHttpNetworkSession(
178 net::URLRequestContext* context) {
179 if (!context->http_transaction_factory())
182 return context->http_transaction_factory()->GetSession();
185 base::Value* ExperimentToValue(const ConnectionTester::Experiment& experiment) {
186 base::DictionaryValue* dict = new base::DictionaryValue();
188 if (experiment.url.is_valid())
189 dict->SetString("url", experiment.url.spec());
191 dict->SetString("proxy_settings_experiment",
192 ConnectionTester::ProxySettingsExperimentDescription(
193 experiment.proxy_settings_experiment));
194 dict->SetString("host_resolver_experiment",
195 ConnectionTester::HostResolverExperimentDescription(
196 experiment.host_resolver_experiment));
200 content::WebUIDataSource* CreateNetInternalsHTMLSource() {
201 content::WebUIDataSource* source =
202 content::WebUIDataSource::Create(chrome::kChromeUINetInternalsHost);
204 source->SetUseJsonJSFormatV2();
205 source->SetDefaultResource(IDR_NET_INTERNALS_INDEX_HTML);
206 source->AddResourcePath("index.js", IDR_NET_INTERNALS_INDEX_JS);
207 source->SetJsonPath("strings.js");
211 #if defined(OS_CHROMEOS)
212 // Small helper class used to create temporary log file and pass its
213 // handle and error status to callback.
215 // DebugLogFileHelper* helper = new DebugLogFileHelper();
216 // base::WorkerPool::PostTaskAndReply(FROM_HERE,
217 // base::Bind(&DebugLogFileHelper::DoWork, base::Unretained(helper), ...),
218 // base::Bind(&DebugLogFileHelper::Reply, base::Owned(helper), ...),
220 class DebugLogFileHelper {
222 typedef base::Callback<void(base::File file,
223 const base::FilePath& file_path)>
224 DebugLogFileCallback;
226 DebugLogFileHelper() {}
228 ~DebugLogFileHelper() {}
230 void DoWork(const base::FilePath& fileshelf) {
231 const base::FilePath::CharType kLogFileName[] =
232 FILE_PATH_LITERAL("debug-log.tgz");
234 file_path_ = fileshelf.Append(kLogFileName);
235 file_path_ = logging::GenerateTimestampedName(file_path_,
238 int flags = base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE;
239 file_.Initialize(file_path_, flags);
242 void Reply(const DebugLogFileCallback& callback) {
243 DCHECK(!callback.is_null());
244 callback.Run(file_.Pass(), file_path_);
249 base::FilePath file_path_;
251 DISALLOW_COPY_AND_ASSIGN(DebugLogFileHelper);
254 // Following functions are used for getting debug logs. Logs are
255 // fetched from /var/log/* and put on the fileshelf.
257 // Called once StoreDebugLogs is complete. Takes two parameters:
258 // - log_path: where the log file was saved in the case of success;
259 // - succeeded: was the log file saved successfully.
260 typedef base::Callback<void(const base::FilePath& log_path,
261 bool succeded)> StoreDebugLogsCallback;
263 // Closes file handle, so, should be called on the WorkerPool thread.
264 void CloseDebugLogFile(base::File file) {
268 // Closes file handle and deletes debug log file, so, should be called
269 // on the WorkerPool thread.
270 void CloseAndDeleteDebugLogFile(base::File file,
271 const base::FilePath& file_path) {
273 base::DeleteFile(file_path, false);
276 // Called upon completion of |WriteDebugLogToFile|. Closes file
277 // descriptor, deletes log file in the case of failure and calls
279 void WriteDebugLogToFileCompleted(const StoreDebugLogsCallback& callback,
281 const base::FilePath& file_path,
283 DCHECK_CURRENTLY_ON(BrowserThread::UI);
285 bool posted = base::WorkerPool::PostTaskAndReply(FROM_HERE,
286 base::Bind(&CloseAndDeleteDebugLogFile, Passed(&file), file_path),
287 base::Bind(callback, file_path, false), false);
291 bool posted = base::WorkerPool::PostTaskAndReply(FROM_HERE,
292 base::Bind(&CloseDebugLogFile, Passed(&file)),
293 base::Bind(callback, file_path, true), false);
297 // Stores into |file_path| debug logs in the .tgz format. Calls
298 // |callback| upon completion.
299 void WriteDebugLogToFile(const StoreDebugLogsCallback& callback,
301 const base::FilePath& file_path) {
302 DCHECK_CURRENTLY_ON(BrowserThread::UI);
303 if (!file.IsValid()) {
305 "Can't create debug log file: " << file_path.AsUTF8Unsafe() << ", " <<
306 "error: " << file.error_details();
309 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->GetDebugLogs(
310 file.GetPlatformFile(),
311 base::Bind(&WriteDebugLogToFileCompleted,
312 callback, Passed(&file), file_path));
315 // Stores debug logs in the .tgz archive on the |fileshelf|. The file
316 // is created on the worker pool, then writing to it is triggered from
317 // the UI thread, and finally it is closed (on success) or deleted (on
318 // failure) on the worker pool, prior to calling |callback|.
319 void StoreDebugLogs(const base::FilePath& fileshelf,
320 const StoreDebugLogsCallback& callback) {
321 DCHECK_CURRENTLY_ON(BrowserThread::UI);
322 DCHECK(!callback.is_null());
323 DebugLogFileHelper* helper = new DebugLogFileHelper();
324 bool posted = base::WorkerPool::PostTaskAndReply(FROM_HERE,
325 base::Bind(&DebugLogFileHelper::DoWork,
326 base::Unretained(helper), fileshelf),
327 base::Bind(&DebugLogFileHelper::Reply, base::Owned(helper),
328 base::Bind(&WriteDebugLogToFile, callback)), false);
331 #endif // defined(OS_CHROMEOS)
333 // This class receives javascript messages from the renderer.
334 // Note that the WebUI infrastructure runs on the UI thread, therefore all of
335 // this class's methods are expected to run on the UI thread.
337 // Since the network code we want to run lives on the IO thread, we proxy
338 // almost everything over to NetInternalsMessageHandler::IOThreadImpl, which
339 // runs on the IO thread.
341 // TODO(eroman): Can we start on the IO thread to begin with?
342 class NetInternalsMessageHandler
343 : public WebUIMessageHandler,
344 public base::SupportsWeakPtr<NetInternalsMessageHandler> {
346 NetInternalsMessageHandler();
347 virtual ~NetInternalsMessageHandler();
349 // WebUIMessageHandler implementation.
350 virtual void RegisterMessages() OVERRIDE;
352 // Calls g_browser.receive in the renderer, passing in |command| and |arg|.
353 // Takes ownership of |arg|. If the renderer is displaying a log file, the
354 // message will be ignored.
355 void SendJavascriptCommand(const std::string& command, base::Value* arg);
357 // Javascript message handlers.
358 void OnRendererReady(const base::ListValue* list);
359 void OnClearBrowserCache(const base::ListValue* list);
360 void OnGetPrerenderInfo(const base::ListValue* list);
361 void OnGetHistoricNetworkStats(const base::ListValue* list);
362 void OnGetExtensionInfo(const base::ListValue* list);
363 #if defined(OS_CHROMEOS)
364 void OnRefreshSystemLogs(const base::ListValue* list);
365 void OnGetSystemLog(const base::ListValue* list);
366 void OnImportONCFile(const base::ListValue* list);
367 void OnStoreDebugLogs(const base::ListValue* list);
368 void OnStoreDebugLogsCompleted(const base::FilePath& log_path,
370 void OnSetNetworkDebugMode(const base::ListValue* list);
371 void OnSetNetworkDebugModeCompleted(const std::string& subsystem,
374 // Callback to |GetNSSCertDatabaseForProfile| used to retrieve the database
375 // to which user's ONC defined certificates should be imported.
376 // It parses and imports |onc_blob|.
377 void ImportONCFileToNSSDB(const std::string& onc_blob,
378 const std::string& passcode,
379 net::NSSCertDatabase* nssdb);
385 #if defined(OS_CHROMEOS)
386 // Class that is used for getting network related ChromeOS logs.
387 // Logs are fetched from ChromeOS libcros on user request, and only when we
388 // don't yet have a copy of logs. If a copy is present, we send back data from
389 // it, else we save request and answer to it when we get logs from libcros.
390 // If needed, we also send request for system logs to libcros.
391 // Logs refresh has to be done explicitly, by deleting old logs and then
392 // loading them again.
393 class SystemLogsGetter {
395 SystemLogsGetter(NetInternalsMessageHandler* handler,
396 chromeos::system::SyslogsProvider* syslogs_provider);
399 // Deletes logs copy we currently have, and resets logs_requested and
400 // logs_received flags.
401 void DeleteSystemLogs();
402 // Starts log fetching. If logs copy is present, requested logs are sent
404 // If syslogs load request hasn't been sent to libcros yet, we do that now,
405 // and postpone sending response.
406 // Request data is specified by args:
407 // $1 : key of the log we are interested in.
408 // $2 : string used to identify request.
409 void RequestSystemLog(const base::ListValue* args);
410 // Requests logs from libcros, but only if we don't have a copy.
411 void LoadSystemLogs();
412 // Processes callback from libcros containing system logs. Postponed
413 // request responses are sent.
414 void OnSystemLogsLoaded(chromeos::system::LogDictionaryType* sys_info,
415 std::string* ignored_content);
418 // Struct we save postponed log request in.
419 struct SystemLogRequest {
424 // Processes request.
425 void SendLogs(const SystemLogRequest& request);
427 NetInternalsMessageHandler* handler_;
428 chromeos::system::SyslogsProvider* syslogs_provider_;
429 // List of postponed requests.
430 std::list<SystemLogRequest> requests_;
431 scoped_ptr<chromeos::system::LogDictionaryType> logs_;
433 bool logs_requested_;
434 base::CancelableTaskTracker tracker_;
435 // Libcros request task ID.
436 base::CancelableTaskTracker::TaskId syslogs_task_id_;
438 #endif // defined(OS_CHROMEOS)
440 // This is the "real" message handler, which lives on the IO thread.
441 scoped_refptr<IOThreadImpl> proxy_;
443 base::WeakPtr<prerender::PrerenderManager> prerender_manager_;
445 #if defined(OS_CHROMEOS)
446 // Class that handles getting and filtering system logs.
447 scoped_ptr<SystemLogsGetter> syslogs_getter_;
450 DISALLOW_COPY_AND_ASSIGN(NetInternalsMessageHandler);
453 // This class is the "real" message handler. It is allocated and destroyed on
454 // the UI thread. With the exception of OnAddEntry, OnWebUIDeleted, and
455 // SendJavascriptCommand, its methods are all expected to be called from the IO
456 // thread. OnAddEntry and SendJavascriptCommand can be called from any thread,
457 // and OnWebUIDeleted can only be called from the UI thread.
458 class NetInternalsMessageHandler::IOThreadImpl
459 : public base::RefCountedThreadSafe<
460 NetInternalsMessageHandler::IOThreadImpl,
461 BrowserThread::DeleteOnUIThread>,
462 public net::NetLog::ThreadSafeObserver,
463 public ConnectionTester::Delegate {
465 // Type for methods that can be used as MessageHandler callbacks.
466 typedef void (IOThreadImpl::*MessageHandler)(const base::ListValue*);
468 // Creates a proxy for |handler| that will live on the IO thread.
469 // |handler| is a weak pointer, since it is possible for the
470 // WebUIMessageHandler to be deleted on the UI thread while we were executing
471 // on the IO thread. |io_thread| is the global IOThread (it is passed in as
472 // an argument since we need to grab it from the UI thread).
474 const base::WeakPtr<NetInternalsMessageHandler>& handler,
476 net::URLRequestContextGetter* main_context_getter);
478 // Called on UI thread just after creation, to add a ContextGetter to
479 // |context_getters_|.
480 void AddRequestContextGetter(net::URLRequestContextGetter* context_getter);
482 // Helper method to enable a callback that will be executed on the IO thread.
483 static void CallbackHelper(MessageHandler method,
484 scoped_refptr<IOThreadImpl> io_thread,
485 const base::ListValue* list);
487 // Called once the WebUI has been deleted (i.e. renderer went away), on the
491 // Called when the WebUI is deleted. Prevents calling Javascript functions
492 // afterwards. Called on UI thread.
493 void OnWebUIDeleted();
495 //--------------------------------
496 // Javascript message handlers:
497 //--------------------------------
499 void OnRendererReady(const base::ListValue* list);
501 void OnGetProxySettings(const base::ListValue* list);
502 void OnReloadProxySettings(const base::ListValue* list);
503 void OnGetBadProxies(const base::ListValue* list);
504 void OnClearBadProxies(const base::ListValue* list);
505 void OnGetHostResolverInfo(const base::ListValue* list);
506 void OnClearHostResolverCache(const base::ListValue* list);
507 void OnEnableIPv6(const base::ListValue* list);
508 void OnStartConnectionTests(const base::ListValue* list);
509 void OnHSTSQuery(const base::ListValue* list);
510 void OnHSTSAdd(const base::ListValue* list);
511 void OnHSTSDelete(const base::ListValue* list);
512 void OnGetHttpCacheInfo(const base::ListValue* list);
513 void OnGetSocketPoolInfo(const base::ListValue* list);
514 void OnGetSessionNetworkStats(const base::ListValue* list);
515 void OnCloseIdleSockets(const base::ListValue* list);
516 void OnFlushSocketPools(const base::ListValue* list);
517 void OnGetSpdySessionInfo(const base::ListValue* list);
518 void OnGetSpdyStatus(const base::ListValue* list);
519 void OnGetSpdyAlternateProtocolMappings(const base::ListValue* list);
520 void OnGetQuicInfo(const base::ListValue* list);
522 void OnGetServiceProviders(const base::ListValue* list);
524 void OnGetHttpPipeliningStatus(const base::ListValue* list);
525 void OnSetLogLevel(const base::ListValue* list);
527 // ChromeNetLog::ThreadSafeObserver implementation:
528 virtual void OnAddEntry(const net::NetLog::Entry& entry) OVERRIDE;
530 // ConnectionTester::Delegate implementation:
531 virtual void OnStartConnectionTestSuite() OVERRIDE;
532 virtual void OnStartConnectionTestExperiment(
533 const ConnectionTester::Experiment& experiment) OVERRIDE;
534 virtual void OnCompletedConnectionTestExperiment(
535 const ConnectionTester::Experiment& experiment,
536 int result) OVERRIDE;
537 virtual void OnCompletedConnectionTestSuite() OVERRIDE;
539 // Helper that calls g_browser.receive in the renderer, passing in |command|
540 // and |arg|. Takes ownership of |arg|. If the renderer is displaying a log
541 // file, the message will be ignored. Note that this can be called from any
543 void SendJavascriptCommand(const std::string& command, base::Value* arg);
546 friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>;
547 friend class base::DeleteHelper<IOThreadImpl>;
549 typedef std::list<scoped_refptr<net::URLRequestContextGetter> >
552 virtual ~IOThreadImpl();
554 // Adds |entry| to the queue of pending log entries to be sent to the page via
555 // Javascript. Must be called on the IO Thread. Also creates a delayed task
556 // that will call PostPendingEntries, if there isn't one already.
557 void AddEntryToQueue(base::Value* entry);
559 // Sends all pending entries to the page via Javascript, and clears the list
560 // of pending entries. Sending multiple entries at once results in a
561 // significant reduction of CPU usage when a lot of events are happening.
562 // Must be called on the IO Thread.
563 void PostPendingEntries();
565 // Adds entries with the states of ongoing URL requests.
566 void PrePopulateEventList();
568 net::URLRequestContext* GetMainContext() {
569 return main_context_getter_->GetURLRequestContext();
572 // Pointer to the UI-thread message handler. Only access this from
574 base::WeakPtr<NetInternalsMessageHandler> handler_;
576 // The global IOThread, which contains the global NetLog to observer.
577 IOThread* io_thread_;
579 // The main URLRequestContextGetter for the tab's profile.
580 scoped_refptr<net::URLRequestContextGetter> main_context_getter_;
582 // Helper that runs the suite of connection tests.
583 scoped_ptr<ConnectionTester> connection_tester_;
585 // True if the Web UI has been deleted. This is used to prevent calling
586 // Javascript functions after the Web UI is destroyed. On refresh, the
587 // messages can end up being sent to the refreshed page, causing duplicate
588 // or partial entries.
590 // This is only read and written to on the UI thread.
591 bool was_webui_deleted_;
593 // Log entries that have yet to be passed along to Javascript page. Non-NULL
594 // when and only when there is a pending delayed task to call
595 // PostPendingEntries. Read and written to exclusively on the IO Thread.
596 scoped_ptr<base::ListValue> pending_entries_;
598 // Used for getting current status of URLRequests when net-internals is
599 // opened. |main_context_getter_| is automatically added on construction.
600 // Duplicates are allowed.
601 ContextGetterList context_getters_;
603 DISALLOW_COPY_AND_ASSIGN(IOThreadImpl);
606 ////////////////////////////////////////////////////////////////////////////////
608 // NetInternalsMessageHandler
610 ////////////////////////////////////////////////////////////////////////////////
612 NetInternalsMessageHandler::NetInternalsMessageHandler() {}
614 NetInternalsMessageHandler::~NetInternalsMessageHandler() {
616 proxy_.get()->OnWebUIDeleted();
617 // Notify the handler on the IO thread that the renderer is gone.
618 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
619 base::Bind(&IOThreadImpl::Detach, proxy_.get()));
623 void NetInternalsMessageHandler::RegisterMessages() {
624 DCHECK_CURRENTLY_ON(BrowserThread::UI);
626 Profile* profile = Profile::FromWebUI(web_ui());
628 proxy_ = new IOThreadImpl(this->AsWeakPtr(), g_browser_process->io_thread(),
629 profile->GetRequestContext());
630 proxy_->AddRequestContextGetter(profile->GetMediaRequestContext());
631 proxy_->AddRequestContextGetter(profile->GetRequestContextForExtensions());
632 #if defined(OS_CHROMEOS)
633 syslogs_getter_.reset(new SystemLogsGetter(this,
634 chromeos::system::SyslogsProvider::GetInstance()));
637 prerender::PrerenderManager* prerender_manager =
638 prerender::PrerenderManagerFactory::GetForProfile(profile);
639 if (prerender_manager) {
640 prerender_manager_ = prerender_manager->AsWeakPtr();
642 prerender_manager_ = base::WeakPtr<prerender::PrerenderManager>();
645 web_ui()->RegisterMessageCallback(
647 base::Bind(&NetInternalsMessageHandler::OnRendererReady,
648 base::Unretained(this)));
649 web_ui()->RegisterMessageCallback(
651 base::Bind(&IOThreadImpl::CallbackHelper,
652 &IOThreadImpl::OnGetProxySettings, proxy_));
653 web_ui()->RegisterMessageCallback(
654 "reloadProxySettings",
655 base::Bind(&IOThreadImpl::CallbackHelper,
656 &IOThreadImpl::OnReloadProxySettings, proxy_));
657 web_ui()->RegisterMessageCallback(
659 base::Bind(&IOThreadImpl::CallbackHelper,
660 &IOThreadImpl::OnGetBadProxies, proxy_));
661 web_ui()->RegisterMessageCallback(
663 base::Bind(&IOThreadImpl::CallbackHelper,
664 &IOThreadImpl::OnClearBadProxies, proxy_));
665 web_ui()->RegisterMessageCallback(
666 "getHostResolverInfo",
667 base::Bind(&IOThreadImpl::CallbackHelper,
668 &IOThreadImpl::OnGetHostResolverInfo, proxy_));
669 web_ui()->RegisterMessageCallback(
670 "clearHostResolverCache",
671 base::Bind(&IOThreadImpl::CallbackHelper,
672 &IOThreadImpl::OnClearHostResolverCache, proxy_));
673 web_ui()->RegisterMessageCallback(
675 base::Bind(&IOThreadImpl::CallbackHelper,
676 &IOThreadImpl::OnEnableIPv6, proxy_));
677 web_ui()->RegisterMessageCallback(
678 "startConnectionTests",
679 base::Bind(&IOThreadImpl::CallbackHelper,
680 &IOThreadImpl::OnStartConnectionTests, proxy_));
681 web_ui()->RegisterMessageCallback(
683 base::Bind(&IOThreadImpl::CallbackHelper,
684 &IOThreadImpl::OnHSTSQuery, proxy_));
685 web_ui()->RegisterMessageCallback(
687 base::Bind(&IOThreadImpl::CallbackHelper,
688 &IOThreadImpl::OnHSTSAdd, proxy_));
689 web_ui()->RegisterMessageCallback(
691 base::Bind(&IOThreadImpl::CallbackHelper,
692 &IOThreadImpl::OnHSTSDelete, proxy_));
693 web_ui()->RegisterMessageCallback(
695 base::Bind(&IOThreadImpl::CallbackHelper,
696 &IOThreadImpl::OnGetHttpCacheInfo, proxy_));
697 web_ui()->RegisterMessageCallback(
699 base::Bind(&IOThreadImpl::CallbackHelper,
700 &IOThreadImpl::OnGetSocketPoolInfo, proxy_));
701 web_ui()->RegisterMessageCallback(
702 "getSessionNetworkStats",
703 base::Bind(&IOThreadImpl::CallbackHelper,
704 &IOThreadImpl::OnGetSessionNetworkStats, proxy_));
705 web_ui()->RegisterMessageCallback(
707 base::Bind(&IOThreadImpl::CallbackHelper,
708 &IOThreadImpl::OnCloseIdleSockets, proxy_));
709 web_ui()->RegisterMessageCallback(
711 base::Bind(&IOThreadImpl::CallbackHelper,
712 &IOThreadImpl::OnFlushSocketPools, proxy_));
713 web_ui()->RegisterMessageCallback(
714 "getSpdySessionInfo",
715 base::Bind(&IOThreadImpl::CallbackHelper,
716 &IOThreadImpl::OnGetSpdySessionInfo, proxy_));
717 web_ui()->RegisterMessageCallback(
719 base::Bind(&IOThreadImpl::CallbackHelper,
720 &IOThreadImpl::OnGetSpdyStatus, proxy_));
721 web_ui()->RegisterMessageCallback(
722 "getSpdyAlternateProtocolMappings",
723 base::Bind(&IOThreadImpl::CallbackHelper,
724 &IOThreadImpl::OnGetSpdyAlternateProtocolMappings, proxy_));
725 web_ui()->RegisterMessageCallback(
727 base::Bind(&IOThreadImpl::CallbackHelper,
728 &IOThreadImpl::OnGetQuicInfo, proxy_));
730 web_ui()->RegisterMessageCallback(
731 "getServiceProviders",
732 base::Bind(&IOThreadImpl::CallbackHelper,
733 &IOThreadImpl::OnGetServiceProviders, proxy_));
736 web_ui()->RegisterMessageCallback(
737 "getHttpPipeliningStatus",
738 base::Bind(&IOThreadImpl::CallbackHelper,
739 &IOThreadImpl::OnGetHttpPipeliningStatus, proxy_));
740 web_ui()->RegisterMessageCallback(
742 base::Bind(&IOThreadImpl::CallbackHelper,
743 &IOThreadImpl::OnSetLogLevel, proxy_));
744 web_ui()->RegisterMessageCallback(
746 base::Bind(&NetInternalsMessageHandler::OnClearBrowserCache,
747 base::Unretained(this)));
748 web_ui()->RegisterMessageCallback(
750 base::Bind(&NetInternalsMessageHandler::OnGetPrerenderInfo,
751 base::Unretained(this)));
752 web_ui()->RegisterMessageCallback(
753 "getHistoricNetworkStats",
754 base::Bind(&NetInternalsMessageHandler::OnGetHistoricNetworkStats,
755 base::Unretained(this)));
756 web_ui()->RegisterMessageCallback(
758 base::Bind(&NetInternalsMessageHandler::OnGetExtensionInfo,
759 base::Unretained(this)));
760 #if defined(OS_CHROMEOS)
761 web_ui()->RegisterMessageCallback(
763 base::Bind(&NetInternalsMessageHandler::OnRefreshSystemLogs,
764 base::Unretained(this)));
765 web_ui()->RegisterMessageCallback(
767 base::Bind(&NetInternalsMessageHandler::OnGetSystemLog,
768 base::Unretained(this)));
769 web_ui()->RegisterMessageCallback(
771 base::Bind(&NetInternalsMessageHandler::OnImportONCFile,
772 base::Unretained(this)));
773 web_ui()->RegisterMessageCallback(
775 base::Bind(&NetInternalsMessageHandler::OnStoreDebugLogs,
776 base::Unretained(this)));
777 web_ui()->RegisterMessageCallback(
778 "setNetworkDebugMode",
779 base::Bind(&NetInternalsMessageHandler::OnSetNetworkDebugMode,
780 base::Unretained(this)));
784 void NetInternalsMessageHandler::SendJavascriptCommand(
785 const std::string& command,
787 scoped_ptr<base::Value> command_value(new base::StringValue(command));
788 scoped_ptr<base::Value> value(arg);
789 DCHECK_CURRENTLY_ON(BrowserThread::UI);
791 web_ui()->CallJavascriptFunction("g_browser.receive",
792 *command_value.get(),
795 web_ui()->CallJavascriptFunction("g_browser.receive",
796 *command_value.get());
800 void NetInternalsMessageHandler::OnRendererReady(const base::ListValue* list) {
801 IOThreadImpl::CallbackHelper(&IOThreadImpl::OnRendererReady, proxy_, list);
804 void NetInternalsMessageHandler::OnClearBrowserCache(
805 const base::ListValue* list) {
806 BrowsingDataRemover* remover = BrowsingDataRemover::CreateForUnboundedRange(
807 Profile::FromWebUI(web_ui()));
808 remover->Remove(BrowsingDataRemover::REMOVE_CACHE,
809 BrowsingDataHelper::UNPROTECTED_WEB);
810 // BrowsingDataRemover deletes itself.
813 void NetInternalsMessageHandler::OnGetPrerenderInfo(
814 const base::ListValue* list) {
815 DCHECK_CURRENTLY_ON(BrowserThread::UI);
817 base::DictionaryValue* value = NULL;
818 prerender::PrerenderManager* prerender_manager = prerender_manager_.get();
819 if (!prerender_manager) {
820 value = new base::DictionaryValue();
821 value->SetBoolean("enabled", false);
822 value->SetBoolean("omnibox_enabled", false);
824 value = prerender_manager->GetAsValue();
826 SendJavascriptCommand("receivedPrerenderInfo", value);
829 void NetInternalsMessageHandler::OnGetHistoricNetworkStats(
830 const base::ListValue* list) {
831 DCHECK_CURRENTLY_ON(BrowserThread::UI);
832 base::Value* historic_network_info =
833 ChromeNetworkDelegate::HistoricNetworkStatsInfoToValue();
834 SendJavascriptCommand("receivedHistoricNetworkStats", historic_network_info);
837 void NetInternalsMessageHandler::OnGetExtensionInfo(
838 const base::ListValue* list) {
839 DCHECK_CURRENTLY_ON(BrowserThread::UI);
840 base::ListValue* extension_list = new base::ListValue();
841 Profile* profile = Profile::FromWebUI(web_ui());
842 extensions::ExtensionSystem* extension_system =
843 extensions::ExtensionSystem::Get(profile);
844 if (extension_system) {
845 ExtensionService* extension_service = extension_system->extension_service();
846 if (extension_service) {
847 scoped_ptr<const extensions::ExtensionSet> extensions(
848 extensions::ExtensionRegistry::Get(profile)
849 ->GenerateInstalledExtensionsSet());
850 for (extensions::ExtensionSet::const_iterator it = extensions->begin();
851 it != extensions->end(); ++it) {
852 base::DictionaryValue* extension_info = new base::DictionaryValue();
853 bool enabled = extension_service->IsExtensionEnabled((*it)->id());
854 extensions::GetExtensionBasicInfo(it->get(), enabled, extension_info);
855 extension_list->Append(extension_info);
859 SendJavascriptCommand("receivedExtensionInfo", extension_list);
862 #if defined(OS_CHROMEOS)
863 ////////////////////////////////////////////////////////////////////////////////
865 // NetInternalsMessageHandler::SystemLogsGetter
867 ////////////////////////////////////////////////////////////////////////////////
869 NetInternalsMessageHandler::SystemLogsGetter::SystemLogsGetter(
870 NetInternalsMessageHandler* handler,
871 chromeos::system::SyslogsProvider* syslogs_provider)
873 syslogs_provider_(syslogs_provider),
874 logs_received_(false),
875 logs_requested_(false) {
876 if (!syslogs_provider_)
877 LOG(ERROR) << "System access library not loaded";
880 NetInternalsMessageHandler::SystemLogsGetter::~SystemLogsGetter() {
884 void NetInternalsMessageHandler::SystemLogsGetter::DeleteSystemLogs() {
885 if (syslogs_provider_ && logs_requested_ && !logs_received_) {
886 tracker_.TryCancel(syslogs_task_id_);
888 logs_requested_ = false;
889 logs_received_ = false;
893 void NetInternalsMessageHandler::SystemLogsGetter::RequestSystemLog(
894 const base::ListValue* args) {
895 if (!logs_requested_) {
896 DCHECK(!logs_received_);
899 SystemLogRequest log_request;
900 args->GetString(0, &log_request.log_key);
901 args->GetString(1, &log_request.cell_id);
903 if (logs_received_) {
904 SendLogs(log_request);
906 requests_.push_back(log_request);
910 void NetInternalsMessageHandler::SystemLogsGetter::LoadSystemLogs() {
911 if (logs_requested_ || !syslogs_provider_)
913 logs_requested_ = true;
914 syslogs_task_id_ = syslogs_provider_->RequestSyslogs(
915 false, // compress logs.
916 chromeos::system::SyslogsProvider::SYSLOGS_NETWORK,
918 &NetInternalsMessageHandler::SystemLogsGetter::OnSystemLogsLoaded,
919 base::Unretained(this)),
923 void NetInternalsMessageHandler::SystemLogsGetter::OnSystemLogsLoaded(
924 chromeos::system::LogDictionaryType* sys_info,
925 std::string* ignored_content) {
926 DCHECK(!ignored_content);
927 logs_.reset(sys_info);
928 logs_received_ = true;
929 for (std::list<SystemLogRequest>::iterator request_it = requests_.begin();
930 request_it != requests_.end();
932 SendLogs(*request_it);
937 void NetInternalsMessageHandler::SystemLogsGetter::SendLogs(
938 const SystemLogRequest& request) {
939 base::DictionaryValue* result = new base::DictionaryValue();
940 chromeos::system::LogDictionaryType::iterator log_it =
941 logs_->find(request.log_key);
942 if (log_it != logs_->end()) {
943 if (!log_it->second.empty()) {
944 result->SetString("log", log_it->second);
946 result->SetString("log", "<no relevant lines found>");
949 result->SetString("log", "<invalid log name>");
951 result->SetString("cellId", request.cell_id);
953 handler_->SendJavascriptCommand("getSystemLogCallback", result);
955 #endif // defined(OS_CHROMEOS)
957 ////////////////////////////////////////////////////////////////////////////////
959 // NetInternalsMessageHandler::IOThreadImpl
961 ////////////////////////////////////////////////////////////////////////////////
963 NetInternalsMessageHandler::IOThreadImpl::IOThreadImpl(
964 const base::WeakPtr<NetInternalsMessageHandler>& handler,
966 net::URLRequestContextGetter* main_context_getter)
968 io_thread_(io_thread),
969 main_context_getter_(main_context_getter),
970 was_webui_deleted_(false) {
971 DCHECK_CURRENTLY_ON(BrowserThread::UI);
972 AddRequestContextGetter(main_context_getter);
975 NetInternalsMessageHandler::IOThreadImpl::~IOThreadImpl() {
976 DCHECK_CURRENTLY_ON(BrowserThread::UI);
979 void NetInternalsMessageHandler::IOThreadImpl::AddRequestContextGetter(
980 net::URLRequestContextGetter* context_getter) {
981 DCHECK_CURRENTLY_ON(BrowserThread::UI);
982 context_getters_.push_back(context_getter);
985 void NetInternalsMessageHandler::IOThreadImpl::CallbackHelper(
986 MessageHandler method,
987 scoped_refptr<IOThreadImpl> io_thread,
988 const base::ListValue* list) {
989 DCHECK_CURRENTLY_ON(BrowserThread::UI);
991 // We need to make a copy of the value in order to pass it over to the IO
992 // thread. |list_copy| will be deleted when the task is destroyed. The called
993 // |method| cannot take ownership of |list_copy|.
994 base::ListValue* list_copy =
995 (list && list->GetSize()) ? list->DeepCopy() : NULL;
997 BrowserThread::PostTask(
998 BrowserThread::IO, FROM_HERE,
999 base::Bind(method, io_thread, base::Owned(list_copy)));
1002 void NetInternalsMessageHandler::IOThreadImpl::Detach() {
1003 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1004 // Unregister with network stack to observe events.
1006 net_log()->RemoveThreadSafeObserver(this);
1008 // Cancel any in-progress connection tests.
1009 connection_tester_.reset();
1012 void NetInternalsMessageHandler::IOThreadImpl::OnWebUIDeleted() {
1013 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1014 was_webui_deleted_ = true;
1017 void NetInternalsMessageHandler::IOThreadImpl::OnRendererReady(
1018 const base::ListValue* list) {
1019 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1021 // If we have any pending entries, go ahead and get rid of them, so they won't
1022 // appear before the REQUEST_ALIVE events we add for currently active
1024 PostPendingEntries();
1026 SendJavascriptCommand("receivedConstants", NetInternalsUI::GetConstants());
1028 // Add entries for ongoing URL requests.
1029 PrePopulateEventList();
1032 // Register with network stack to observe events.
1033 io_thread_->net_log()->AddThreadSafeObserver(this,
1034 net::NetLog::LOG_ALL_BUT_BYTES);
1038 void NetInternalsMessageHandler::IOThreadImpl::OnGetProxySettings(
1039 const base::ListValue* list) {
1041 net::ProxyService* proxy_service = GetMainContext()->proxy_service();
1043 base::DictionaryValue* dict = new base::DictionaryValue();
1044 if (proxy_service->fetched_config().is_valid())
1045 dict->Set("original", proxy_service->fetched_config().ToValue());
1046 if (proxy_service->config().is_valid())
1047 dict->Set("effective", proxy_service->config().ToValue());
1049 SendJavascriptCommand("receivedProxySettings", dict);
1052 void NetInternalsMessageHandler::IOThreadImpl::OnReloadProxySettings(
1053 const base::ListValue* list) {
1055 GetMainContext()->proxy_service()->ForceReloadProxyConfig();
1057 // Cause the renderer to be notified of the new values.
1058 OnGetProxySettings(NULL);
1061 void NetInternalsMessageHandler::IOThreadImpl::OnGetBadProxies(
1062 const base::ListValue* list) {
1065 const net::ProxyRetryInfoMap& bad_proxies_map =
1066 GetMainContext()->proxy_service()->proxy_retry_info();
1068 base::ListValue* dict_list = new base::ListValue();
1070 for (net::ProxyRetryInfoMap::const_iterator it = bad_proxies_map.begin();
1071 it != bad_proxies_map.end(); ++it) {
1072 const std::string& proxy_uri = it->first;
1073 const net::ProxyRetryInfo& retry_info = it->second;
1075 base::DictionaryValue* dict = new base::DictionaryValue();
1076 dict->SetString("proxy_uri", proxy_uri);
1077 dict->SetString("bad_until",
1078 net::NetLog::TickCountToString(retry_info.bad_until));
1080 dict_list->Append(dict);
1083 SendJavascriptCommand("receivedBadProxies", dict_list);
1086 void NetInternalsMessageHandler::IOThreadImpl::OnClearBadProxies(
1087 const base::ListValue* list) {
1089 GetMainContext()->proxy_service()->ClearBadProxiesCache();
1091 // Cause the renderer to be notified of the new values.
1092 OnGetBadProxies(NULL);
1095 void NetInternalsMessageHandler::IOThreadImpl::OnGetHostResolverInfo(
1096 const base::ListValue* list) {
1098 net::URLRequestContext* context = GetMainContext();
1099 net::HostCache* cache = GetHostResolverCache(context);
1102 SendJavascriptCommand("receivedHostResolverInfo", NULL);
1106 base::DictionaryValue* dict = new base::DictionaryValue();
1108 base::Value* dns_config = context->host_resolver()->GetDnsConfigAsValue();
1110 dict->Set("dns_config", dns_config);
1113 "default_address_family",
1114 static_cast<int>(context->host_resolver()->GetDefaultAddressFamily()));
1116 base::DictionaryValue* cache_info_dict = new base::DictionaryValue();
1118 cache_info_dict->SetInteger(
1120 static_cast<int>(cache->max_entries()));
1122 base::ListValue* entry_list = new base::ListValue();
1124 net::HostCache::EntryMap::Iterator it(cache->entries());
1125 for (; it.HasNext(); it.Advance()) {
1126 const net::HostCache::Key& key = it.key();
1127 const net::HostCache::Entry& entry = it.value();
1129 base::DictionaryValue* entry_dict = new base::DictionaryValue();
1131 entry_dict->SetString("hostname", key.hostname);
1132 entry_dict->SetInteger("address_family",
1133 static_cast<int>(key.address_family));
1134 entry_dict->SetString("expiration",
1135 net::NetLog::TickCountToString(it.expiration()));
1137 if (entry.error != net::OK) {
1138 entry_dict->SetInteger("error", entry.error);
1140 // Append all of the resolved addresses.
1141 base::ListValue* address_list = new base::ListValue();
1142 for (size_t i = 0; i < entry.addrlist.size(); ++i) {
1143 address_list->AppendString(entry.addrlist[i].ToStringWithoutPort());
1145 entry_dict->Set("addresses", address_list);
1148 entry_list->Append(entry_dict);
1151 cache_info_dict->Set("entries", entry_list);
1152 dict->Set("cache", cache_info_dict);
1154 SendJavascriptCommand("receivedHostResolverInfo", dict);
1157 void NetInternalsMessageHandler::IOThreadImpl::OnClearHostResolverCache(
1158 const base::ListValue* list) {
1160 net::HostCache* cache = GetHostResolverCache(GetMainContext());
1165 // Cause the renderer to be notified of the new values.
1166 OnGetHostResolverInfo(NULL);
1169 void NetInternalsMessageHandler::IOThreadImpl::OnEnableIPv6(
1170 const base::ListValue* list) {
1172 net::HostResolver* host_resolver = GetMainContext()->host_resolver();
1174 host_resolver->SetDefaultAddressFamily(net::ADDRESS_FAMILY_UNSPECIFIED);
1176 // Cause the renderer to be notified of the new value.
1177 OnGetHostResolverInfo(NULL);
1180 void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTests(
1181 const base::ListValue* list) {
1182 // |value| should be: [<URL to test>].
1183 base::string16 url_str;
1184 CHECK(list->GetString(0, &url_str));
1186 // Try to fix-up the user provided URL into something valid.
1187 // For example, turn "www.google.com" into "http://www.google.com".
1188 GURL url(URLFixerUpper::FixupURL(base::UTF16ToUTF8(url_str), std::string()));
1190 connection_tester_.reset(new ConnectionTester(
1192 io_thread_->globals()->proxy_script_fetcher_context.get(),
1194 connection_tester_->RunAllTests(url);
1197 void NetInternalsMessageHandler::IOThreadImpl::OnHSTSQuery(
1198 const base::ListValue* list) {
1199 // |list| should be: [<domain to query>].
1201 CHECK(list->GetString(0, &domain));
1202 base::DictionaryValue* result = new base::DictionaryValue();
1204 if (!base::IsStringASCII(domain)) {
1205 result->SetString("error", "non-ASCII domain name");
1207 net::TransportSecurityState* transport_security_state =
1208 GetMainContext()->transport_security_state();
1209 if (!transport_security_state) {
1210 result->SetString("error", "no TransportSecurityState active");
1212 net::TransportSecurityState::DomainState static_state;
1213 const bool found_static = transport_security_state->GetStaticDomainState(
1214 domain, true, &static_state);
1216 result->SetBoolean("has_static_sts",
1217 found_static && static_state.ShouldUpgradeToSSL());
1218 result->SetInteger("static_upgrade_mode",
1219 static_cast<int>(static_state.sts.upgrade_mode));
1220 result->SetBoolean("static_sts_include_subdomains",
1221 static_state.sts.include_subdomains);
1222 result->SetDouble("static_sts_observed",
1223 static_state.sts.last_observed.ToDoubleT());
1224 result->SetDouble("static_sts_expiry",
1225 static_state.sts.expiry.ToDoubleT());
1226 result->SetBoolean("has_static_pkp",
1227 found_static && static_state.HasPublicKeyPins());
1228 result->SetBoolean("static_pkp_include_subdomains",
1229 static_state.pkp.include_subdomains);
1230 result->SetDouble("static_pkp_observed",
1231 static_state.pkp.last_observed.ToDoubleT());
1232 result->SetDouble("static_pkp_expiry",
1233 static_state.pkp.expiry.ToDoubleT());
1234 result->SetString("static_spki_hashes",
1235 HashesToBase64String(static_state.pkp.spki_hashes));
1238 net::TransportSecurityState::DomainState dynamic_state;
1239 const bool found_dynamic =
1240 transport_security_state->GetDynamicDomainState(domain,
1242 if (found_dynamic) {
1243 result->SetInteger("dynamic_upgrade_mode",
1244 static_cast<int>(dynamic_state.sts.upgrade_mode));
1245 result->SetBoolean("dynamic_sts_include_subdomains",
1246 dynamic_state.sts.include_subdomains);
1247 result->SetBoolean("dynamic_pkp_include_subdomains",
1248 dynamic_state.pkp.include_subdomains);
1249 result->SetDouble("dynamic_sts_observed",
1250 dynamic_state.sts.last_observed.ToDoubleT());
1251 result->SetDouble("dynamic_pkp_observed",
1252 dynamic_state.pkp.last_observed.ToDoubleT());
1253 result->SetDouble("dynamic_sts_expiry",
1254 dynamic_state.sts.expiry.ToDoubleT());
1255 result->SetDouble("dynamic_pkp_expiry",
1256 dynamic_state.pkp.expiry.ToDoubleT());
1257 result->SetString("dynamic_spki_hashes",
1258 HashesToBase64String(dynamic_state.pkp.spki_hashes));
1261 result->SetBoolean("result", found_static || found_dynamic);
1263 result->SetString("domain", static_state.domain);
1264 } else if (found_dynamic) {
1265 result->SetString("domain", dynamic_state.domain);
1267 result->SetString("domain", domain);
1272 SendJavascriptCommand("receivedHSTSResult", result);
1275 void NetInternalsMessageHandler::IOThreadImpl::OnHSTSAdd(
1276 const base::ListValue* list) {
1277 // |list| should be: [<domain to query>, <STS include subdomains>, <PKP
1278 // include subdomains>, <key pins>].
1280 CHECK(list->GetString(0, &domain));
1281 if (!base::IsStringASCII(domain)) {
1282 // Silently fail. The user will get a helpful error if they query for the
1286 bool sts_include_subdomains;
1287 CHECK(list->GetBoolean(1, &sts_include_subdomains));
1288 bool pkp_include_subdomains;
1289 CHECK(list->GetBoolean(2, &pkp_include_subdomains));
1290 std::string hashes_str;
1291 CHECK(list->GetString(3, &hashes_str));
1293 net::TransportSecurityState* transport_security_state =
1294 GetMainContext()->transport_security_state();
1295 if (!transport_security_state)
1298 base::Time expiry = base::Time::Now() + base::TimeDelta::FromDays(1000);
1299 net::HashValueVector hashes;
1300 if (!hashes_str.empty()) {
1301 if (!Base64StringToHashes(hashes_str, &hashes))
1305 transport_security_state->AddHSTS(domain, expiry, sts_include_subdomains);
1306 transport_security_state->AddHPKP(domain, expiry, pkp_include_subdomains,
1310 void NetInternalsMessageHandler::IOThreadImpl::OnHSTSDelete(
1311 const base::ListValue* list) {
1312 // |list| should be: [<domain to query>].
1314 CHECK(list->GetString(0, &domain));
1315 if (!base::IsStringASCII(domain)) {
1316 // There cannot be a unicode entry in the HSTS set.
1319 net::TransportSecurityState* transport_security_state =
1320 GetMainContext()->transport_security_state();
1321 if (!transport_security_state)
1324 transport_security_state->DeleteDynamicDataForHost(domain);
1327 void NetInternalsMessageHandler::IOThreadImpl::OnGetHttpCacheInfo(
1328 const base::ListValue* list) {
1330 base::DictionaryValue* info_dict = new base::DictionaryValue();
1331 base::DictionaryValue* stats_dict = new base::DictionaryValue();
1333 disk_cache::Backend* disk_cache = GetDiskCacheBackend(GetMainContext());
1336 // Extract the statistics key/value pairs from the backend.
1337 std::vector<std::pair<std::string, std::string> > stats;
1338 disk_cache->GetStats(&stats);
1339 for (size_t i = 0; i < stats.size(); ++i) {
1340 stats_dict->SetStringWithoutPathExpansion(
1341 stats[i].first, stats[i].second);
1345 info_dict->Set("stats", stats_dict);
1347 SendJavascriptCommand("receivedHttpCacheInfo", info_dict);
1350 void NetInternalsMessageHandler::IOThreadImpl::OnGetSocketPoolInfo(
1351 const base::ListValue* list) {
1353 net::HttpNetworkSession* http_network_session =
1354 GetHttpNetworkSession(GetMainContext());
1356 base::Value* socket_pool_info = NULL;
1357 if (http_network_session)
1358 socket_pool_info = http_network_session->SocketPoolInfoToValue();
1360 SendJavascriptCommand("receivedSocketPoolInfo", socket_pool_info);
1363 void NetInternalsMessageHandler::IOThreadImpl::OnGetSessionNetworkStats(
1364 const base::ListValue* list) {
1366 net::HttpNetworkSession* http_network_session =
1367 GetHttpNetworkSession(main_context_getter_->GetURLRequestContext());
1369 base::Value* network_info = NULL;
1370 if (http_network_session) {
1371 ChromeNetworkDelegate* net_delegate =
1372 static_cast<ChromeNetworkDelegate*>(
1373 http_network_session->network_delegate());
1375 network_info = net_delegate->SessionNetworkStatsInfoToValue();
1378 SendJavascriptCommand("receivedSessionNetworkStats", network_info);
1381 void NetInternalsMessageHandler::IOThreadImpl::OnFlushSocketPools(
1382 const base::ListValue* list) {
1384 net::HttpNetworkSession* http_network_session =
1385 GetHttpNetworkSession(GetMainContext());
1387 if (http_network_session)
1388 http_network_session->CloseAllConnections();
1391 void NetInternalsMessageHandler::IOThreadImpl::OnCloseIdleSockets(
1392 const base::ListValue* list) {
1394 net::HttpNetworkSession* http_network_session =
1395 GetHttpNetworkSession(GetMainContext());
1397 if (http_network_session)
1398 http_network_session->CloseIdleConnections();
1401 void NetInternalsMessageHandler::IOThreadImpl::OnGetSpdySessionInfo(
1402 const base::ListValue* list) {
1404 net::HttpNetworkSession* http_network_session =
1405 GetHttpNetworkSession(GetMainContext());
1407 base::Value* spdy_info = http_network_session ?
1408 http_network_session->SpdySessionPoolInfoToValue() : NULL;
1409 SendJavascriptCommand("receivedSpdySessionInfo", spdy_info);
1412 void NetInternalsMessageHandler::IOThreadImpl::OnGetSpdyStatus(
1413 const base::ListValue* list) {
1415 base::DictionaryValue* status_dict = new base::DictionaryValue();
1417 status_dict->Set("spdy_enabled",
1418 base::Value::CreateBooleanValue(
1419 net::HttpStreamFactory::spdy_enabled()));
1420 status_dict->Set("use_alternate_protocols",
1421 base::Value::CreateBooleanValue(
1422 net::HttpStreamFactory::use_alternate_protocols()));
1423 status_dict->Set("force_spdy_over_ssl",
1424 base::Value::CreateBooleanValue(
1425 net::HttpStreamFactory::force_spdy_over_ssl()));
1426 status_dict->Set("force_spdy_always",
1427 base::Value::CreateBooleanValue(
1428 net::HttpStreamFactory::force_spdy_always()));
1430 // The next_protos may not be specified for certain configurations of SPDY.
1431 std::string next_protos_string;
1432 if (net::HttpStreamFactory::has_next_protos()) {
1433 next_protos_string = JoinString(net::HttpStreamFactory::next_protos(), ',');
1435 status_dict->SetString("next_protos", next_protos_string);
1437 SendJavascriptCommand("receivedSpdyStatus", status_dict);
1441 NetInternalsMessageHandler::IOThreadImpl::OnGetSpdyAlternateProtocolMappings(
1442 const base::ListValue* list) {
1444 base::ListValue* dict_list = new base::ListValue();
1446 const net::HttpServerProperties& http_server_properties =
1447 *GetMainContext()->http_server_properties();
1449 const net::AlternateProtocolMap& map =
1450 http_server_properties.alternate_protocol_map();
1452 for (net::AlternateProtocolMap::const_iterator it = map.begin();
1453 it != map.end(); ++it) {
1454 base::DictionaryValue* dict = new base::DictionaryValue();
1455 dict->SetString("host_port_pair", it->first.ToString());
1456 dict->SetString("alternate_protocol", it->second.ToString());
1457 dict_list->Append(dict);
1460 SendJavascriptCommand("receivedSpdyAlternateProtocolMappings", dict_list);
1463 void NetInternalsMessageHandler::IOThreadImpl::OnGetQuicInfo(
1464 const base::ListValue* list) {
1466 net::HttpNetworkSession* http_network_session =
1467 GetHttpNetworkSession(GetMainContext());
1469 base::Value* quic_info = http_network_session ?
1470 http_network_session->QuicInfoToValue() : NULL;
1471 SendJavascriptCommand("receivedQuicInfo", quic_info);
1475 void NetInternalsMessageHandler::IOThreadImpl::OnGetServiceProviders(
1476 const base::ListValue* list) {
1479 base::DictionaryValue* service_providers = new base::DictionaryValue();
1481 WinsockLayeredServiceProviderList layered_providers;
1482 GetWinsockLayeredServiceProviders(&layered_providers);
1483 base::ListValue* layered_provider_list = new base::ListValue();
1484 for (size_t i = 0; i < layered_providers.size(); ++i) {
1485 base::DictionaryValue* service_dict = new base::DictionaryValue();
1486 service_dict->SetString("name", layered_providers[i].name);
1487 service_dict->SetInteger("version", layered_providers[i].version);
1488 service_dict->SetInteger("chain_length", layered_providers[i].chain_length);
1489 service_dict->SetInteger("socket_type", layered_providers[i].socket_type);
1490 service_dict->SetInteger("socket_protocol",
1491 layered_providers[i].socket_protocol);
1492 service_dict->SetString("path", layered_providers[i].path);
1494 layered_provider_list->Append(service_dict);
1496 service_providers->Set("service_providers", layered_provider_list);
1498 WinsockNamespaceProviderList namespace_providers;
1499 GetWinsockNamespaceProviders(&namespace_providers);
1500 base::ListValue* namespace_list = new base::ListValue;
1501 for (size_t i = 0; i < namespace_providers.size(); ++i) {
1502 base::DictionaryValue* namespace_dict = new base::DictionaryValue();
1503 namespace_dict->SetString("name", namespace_providers[i].name);
1504 namespace_dict->SetBoolean("active", namespace_providers[i].active);
1505 namespace_dict->SetInteger("version", namespace_providers[i].version);
1506 namespace_dict->SetInteger("type", namespace_providers[i].type);
1508 namespace_list->Append(namespace_dict);
1510 service_providers->Set("namespace_providers", namespace_list);
1512 SendJavascriptCommand("receivedServiceProviders", service_providers);
1516 #if defined(OS_CHROMEOS)
1517 void NetInternalsMessageHandler::OnRefreshSystemLogs(
1518 const base::ListValue* list) {
1520 DCHECK(syslogs_getter_.get());
1521 syslogs_getter_->DeleteSystemLogs();
1522 syslogs_getter_->LoadSystemLogs();
1525 void NetInternalsMessageHandler::OnGetSystemLog(
1526 const base::ListValue* list) {
1527 DCHECK(syslogs_getter_.get());
1528 syslogs_getter_->RequestSystemLog(list);
1531 void NetInternalsMessageHandler::ImportONCFileToNSSDB(
1532 const std::string& onc_blob,
1533 const std::string& passcode,
1534 net::NSSCertDatabase* nssdb) {
1536 chromeos::User* user = chromeos::UserManager::Get()->GetUserByProfile(
1537 Profile::FromWebUI(web_ui()));
1540 onc::ONCSource onc_source = onc::ONC_SOURCE_USER_IMPORT;
1542 base::ListValue network_configs;
1543 base::DictionaryValue global_network_config;
1544 base::ListValue certificates;
1545 if (!chromeos::onc::ParseAndValidateOncForImport(onc_blob,
1549 &global_network_config,
1551 error = "Errors occurred during the ONC parsing. ";
1554 chromeos::onc::CertificateImporterImpl cert_importer(nssdb);
1555 if (!cert_importer.ImportCertificates(certificates, onc_source, NULL))
1556 error += "Some certificates couldn't be imported. ";
1558 std::string network_error;
1559 chromeos::onc::ImportNetworksForUser(user, network_configs, &network_error);
1560 if (!network_error.empty())
1561 error += network_error;
1563 error = "User not found.";
1566 LOG_IF(ERROR, !error.empty()) << error;
1567 SendJavascriptCommand("receivedONCFileParse", new base::StringValue(error));
1570 void NetInternalsMessageHandler::OnImportONCFile(
1571 const base::ListValue* list) {
1572 std::string onc_blob;
1573 std::string passcode;
1574 if (list->GetSize() != 2 ||
1575 !list->GetString(0, &onc_blob) ||
1576 !list->GetString(1, &passcode)) {
1580 GetNSSCertDatabaseForProfile(
1581 Profile::FromWebUI(web_ui()),
1582 base::Bind(&NetInternalsMessageHandler::ImportONCFileToNSSDB, AsWeakPtr(),
1583 onc_blob, passcode));
1586 void NetInternalsMessageHandler::OnStoreDebugLogs(const base::ListValue* list) {
1589 SendJavascriptCommand("receivedStoreDebugLogs",
1590 new base::StringValue("Creating log file..."));
1591 const DownloadPrefs* const prefs =
1592 DownloadPrefs::FromBrowserContext(Profile::FromWebUI(web_ui()));
1593 StoreDebugLogs(prefs->DownloadPath(),
1594 base::Bind(&NetInternalsMessageHandler::OnStoreDebugLogsCompleted,
1598 void NetInternalsMessageHandler::OnStoreDebugLogsCompleted(
1599 const base::FilePath& log_path, bool succeeded) {
1602 status = "Created log file: " + log_path.BaseName().AsUTF8Unsafe();
1604 status = "Failed to create log file";
1605 SendJavascriptCommand("receivedStoreDebugLogs",
1606 new base::StringValue(status));
1609 void NetInternalsMessageHandler::OnSetNetworkDebugMode(
1610 const base::ListValue* list) {
1611 std::string subsystem;
1612 if (list->GetSize() != 1 || !list->GetString(0, &subsystem))
1614 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->
1618 &NetInternalsMessageHandler::OnSetNetworkDebugModeCompleted,
1623 void NetInternalsMessageHandler::OnSetNetworkDebugModeCompleted(
1624 const std::string& subsystem,
1628 status = "Debug mode is changed to " + subsystem;
1630 status = "Failed to change debug mode to " + subsystem;
1631 SendJavascriptCommand("receivedSetNetworkDebugMode",
1632 new base::StringValue(status));
1634 #endif // defined(OS_CHROMEOS)
1636 void NetInternalsMessageHandler::IOThreadImpl::OnGetHttpPipeliningStatus(
1637 const base::ListValue* list) {
1639 base::DictionaryValue* status_dict = new base::DictionaryValue();
1641 base::Value* pipelined_connection_info = NULL;
1642 net::HttpNetworkSession* http_network_session =
1643 GetHttpNetworkSession(GetMainContext());
1644 if (http_network_session) {
1645 status_dict->Set("pipelining_enabled", base::Value::CreateBooleanValue(
1646 http_network_session->params().http_pipelining_enabled));
1648 pipelined_connection_info =
1649 http_network_session->http_stream_factory()->PipelineInfoToValue();
1651 status_dict->Set("pipelined_connection_info", pipelined_connection_info);
1653 const net::HttpServerProperties& http_server_properties =
1654 *GetMainContext()->http_server_properties();
1656 // TODO(simonjam): This call is slow.
1657 const net::PipelineCapabilityMap pipeline_capability_map =
1658 http_server_properties.GetPipelineCapabilityMap();
1660 base::ListValue* known_hosts_list = new base::ListValue();
1661 net::PipelineCapabilityMap::const_iterator it;
1662 for (it = pipeline_capability_map.begin();
1663 it != pipeline_capability_map.end(); ++it) {
1664 base::DictionaryValue* host_dict = new base::DictionaryValue();
1665 host_dict->SetString("host", it->first.ToString());
1666 std::string capability;
1667 switch (it->second) {
1668 case net::PIPELINE_CAPABLE:
1669 capability = "capable";
1672 case net::PIPELINE_PROBABLY_CAPABLE:
1673 capability = "probably capable";
1676 case net::PIPELINE_INCAPABLE:
1677 capability = "incapable";
1680 case net::PIPELINE_UNKNOWN:
1682 capability = "unknown";
1685 host_dict->SetString("capability", capability);
1686 known_hosts_list->Append(host_dict);
1688 status_dict->Set("pipelined_host_info", known_hosts_list);
1690 SendJavascriptCommand("receivedHttpPipeliningStatus", status_dict);
1693 void NetInternalsMessageHandler::IOThreadImpl::OnSetLogLevel(
1694 const base::ListValue* list) {
1696 std::string log_level_string;
1697 if (!list->GetString(0, &log_level_string) ||
1698 !base::StringToInt(log_level_string, &log_level)) {
1703 DCHECK_GE(log_level, net::NetLog::LOG_ALL);
1704 DCHECK_LT(log_level, net::NetLog::LOG_NONE);
1705 net_log()->SetObserverLogLevel(
1706 this, static_cast<net::NetLog::LogLevel>(log_level));
1709 // Note that unlike other methods of IOThreadImpl, this function
1710 // can be called from ANY THREAD.
1711 void NetInternalsMessageHandler::IOThreadImpl::OnAddEntry(
1712 const net::NetLog::Entry& entry) {
1713 BrowserThread::PostTask(
1714 BrowserThread::IO, FROM_HERE,
1715 base::Bind(&IOThreadImpl::AddEntryToQueue, this, entry.ToValue()));
1718 void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTestSuite() {
1719 SendJavascriptCommand("receivedStartConnectionTestSuite", NULL);
1722 void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTestExperiment(
1723 const ConnectionTester::Experiment& experiment) {
1724 SendJavascriptCommand(
1725 "receivedStartConnectionTestExperiment",
1726 ExperimentToValue(experiment));
1730 NetInternalsMessageHandler::IOThreadImpl::OnCompletedConnectionTestExperiment(
1731 const ConnectionTester::Experiment& experiment,
1733 base::DictionaryValue* dict = new base::DictionaryValue();
1735 dict->Set("experiment", ExperimentToValue(experiment));
1736 dict->SetInteger("result", result);
1738 SendJavascriptCommand(
1739 "receivedCompletedConnectionTestExperiment",
1744 NetInternalsMessageHandler::IOThreadImpl::OnCompletedConnectionTestSuite() {
1745 SendJavascriptCommand(
1746 "receivedCompletedConnectionTestSuite",
1750 // Note that this can be called from ANY THREAD.
1751 void NetInternalsMessageHandler::IOThreadImpl::SendJavascriptCommand(
1752 const std::string& command,
1754 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
1755 if (handler_.get() && !was_webui_deleted_) {
1756 // We check |handler_| in case it was deleted on the UI thread earlier
1757 // while we were running on the IO thread.
1758 handler_->SendJavascriptCommand(command, arg);
1765 if (!BrowserThread::PostTask(
1766 BrowserThread::UI, FROM_HERE,
1767 base::Bind(&IOThreadImpl::SendJavascriptCommand, this, command, arg))) {
1768 // Failed posting the task, avoid leaking.
1773 void NetInternalsMessageHandler::IOThreadImpl::AddEntryToQueue(
1774 base::Value* entry) {
1775 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1776 if (!pending_entries_.get()) {
1777 pending_entries_.reset(new base::ListValue());
1778 BrowserThread::PostDelayedTask(
1779 BrowserThread::IO, FROM_HERE,
1780 base::Bind(&IOThreadImpl::PostPendingEntries, this),
1781 base::TimeDelta::FromMilliseconds(kNetLogEventDelayMilliseconds));
1783 pending_entries_->Append(entry);
1786 void NetInternalsMessageHandler::IOThreadImpl::PostPendingEntries() {
1787 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1788 if (pending_entries_.get())
1789 SendJavascriptCommand("receivedLogEntries", pending_entries_.release());
1792 void NetInternalsMessageHandler::IOThreadImpl::PrePopulateEventList() {
1793 // Use a set to prevent duplicates.
1794 std::set<net::URLRequestContext*> contexts;
1795 for (ContextGetterList::const_iterator getter = context_getters_.begin();
1796 getter != context_getters_.end(); ++getter) {
1797 contexts.insert((*getter)->GetURLRequestContext());
1799 contexts.insert(io_thread_->globals()->proxy_script_fetcher_context.get());
1800 contexts.insert(io_thread_->globals()->system_request_context.get());
1802 // Put together the list of all requests.
1803 std::vector<const net::URLRequest*> requests;
1804 for (std::set<net::URLRequestContext*>::const_iterator context =
1806 context != contexts.end(); ++context) {
1807 std::set<const net::URLRequest*>* context_requests =
1808 (*context)->url_requests();
1809 for (std::set<const net::URLRequest*>::const_iterator request_it =
1810 context_requests->begin();
1811 request_it != context_requests->end(); ++request_it) {
1812 DCHECK_EQ(io_thread_->net_log(), (*request_it)->net_log().net_log());
1813 requests.push_back(*request_it);
1817 // Sort by creation time.
1818 std::sort(requests.begin(), requests.end(), RequestCreatedBefore);
1820 // Create fake events.
1821 for (std::vector<const net::URLRequest*>::const_iterator request_it =
1823 request_it != requests.end(); ++request_it) {
1824 const net::URLRequest* request = *request_it;
1825 net::NetLog::ParametersCallback callback =
1826 base::Bind(&GetRequestStateAsValue, base::Unretained(request));
1828 // Create and add the entry directly, to avoid sending it to any other
1829 // NetLog observers.
1830 net::NetLog::EntryData entry_data(net::NetLog::TYPE_REQUEST_ALIVE,
1831 request->net_log().source(),
1832 net::NetLog::PHASE_BEGIN,
1833 request->creation_time(),
1835 net::NetLog::Entry entry(&entry_data, request->net_log().GetLogLevel());
1837 // Have to add |entry| to the queue synchronously, as there may already
1838 // be posted tasks queued up to add other events for |request|, which we
1839 // want |entry| to precede.
1840 AddEntryToQueue(entry.ToValue());
1847 ////////////////////////////////////////////////////////////////////////////////
1851 ////////////////////////////////////////////////////////////////////////////////
1854 base::Value* NetInternalsUI::GetConstants() {
1855 base::DictionaryValue* constants_dict = net::NetLogLogger::GetConstants();
1856 DCHECK(constants_dict);
1858 // Add a dictionary with the version of the client and its command line
1861 base::DictionaryValue* dict = new base::DictionaryValue();
1863 chrome::VersionInfo version_info;
1865 if (!version_info.is_valid()) {
1866 DLOG(ERROR) << "Unable to create chrome::VersionInfo";
1868 // We have everything we need to send the right values.
1869 dict->SetString("name", version_info.Name());
1870 dict->SetString("version", version_info.Version());
1871 dict->SetString("cl", version_info.LastChange());
1872 dict->SetString("version_mod",
1873 chrome::VersionInfo::GetVersionStringModifier());
1874 dict->SetString("official",
1875 version_info.IsOfficialBuild() ? "official" :
1877 dict->SetString("os_type", version_info.OSType());
1878 dict->SetString("command_line",
1879 CommandLine::ForCurrentProcess()->GetCommandLineString());
1882 constants_dict->Set("clientInfo", dict);
1885 return constants_dict;
1888 NetInternalsUI::NetInternalsUI(content::WebUI* web_ui)
1889 : WebUIController(web_ui) {
1890 web_ui->AddMessageHandler(new NetInternalsMessageHandler());
1892 // Set up the chrome://net-internals/ source.
1893 Profile* profile = Profile::FromWebUI(web_ui);
1894 content::WebUIDataSource::Add(profile, CreateNetInternalsHTMLSource());