Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / ui / webui / net_internals / net_internals_ui.cc
blob1058e076e060f205bd3f9aaabfedfb4b63a9c8d2
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"
7 #include <algorithm>
8 #include <list>
9 #include <string>
10 #include <utility>
11 #include <vector>
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_path.h"
19 #include "base/memory/weak_ptr.h"
20 #include "base/message_loop/message_loop.h"
21 #include "base/platform_file.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/threading/worker_pool.h"
30 #include "base/values.h"
31 #include "chrome/browser/browser_process.h"
32 #include "chrome/browser/browsing_data/browsing_data_helper.h"
33 #include "chrome/browser/browsing_data/browsing_data_remover.h"
34 #include "chrome/browser/chrome_notification_types.h"
35 #include "chrome/browser/download/download_prefs.h"
36 #include "chrome/browser/extensions/extension_service.h"
37 #include "chrome/browser/extensions/extension_system.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/cancelable_task_tracker.h"
47 #include "chrome/common/chrome_paths.h"
48 #include "chrome/common/chrome_version_info.h"
49 #include "chrome/common/logging_chrome.h"
50 #include "chrome/common/net/url_fixer_upper.h"
51 #include "chrome/common/pref_names.h"
52 #include "chrome/common/url_constants.h"
53 #include "components/onc/onc_constants.h"
54 #include "content/public/browser/browser_thread.h"
55 #include "content/public/browser/notification_details.h"
56 #include "content/public/browser/resource_dispatcher_host.h"
57 #include "content/public/browser/web_contents.h"
58 #include "content/public/browser/web_ui.h"
59 #include "content/public/browser/web_ui_data_source.h"
60 #include "content/public/browser/web_ui_message_handler.h"
61 #include "extensions/common/extension_set.h"
62 #include "grit/generated_resources.h"
63 #include "grit/net_internals_resources.h"
64 #include "net/base/net_errors.h"
65 #include "net/base/net_log_logger.h"
66 #include "net/base/net_util.h"
67 #include "net/disk_cache/disk_cache.h"
68 #include "net/dns/host_cache.h"
69 #include "net/dns/host_resolver.h"
70 #include "net/http/http_cache.h"
71 #include "net/http/http_network_layer.h"
72 #include "net/http/http_network_session.h"
73 #include "net/http/http_server_properties.h"
74 #include "net/http/http_stream_factory.h"
75 #include "net/http/transport_security_state.h"
76 #include "net/proxy/proxy_service.h"
77 #include "net/url_request/url_request_context.h"
78 #include "net/url_request/url_request_context_getter.h"
79 #include "ui/base/resource/resource_bundle.h"
81 #if defined(OS_CHROMEOS)
82 #include "chrome/browser/chromeos/login/user.h"
83 #include "chrome/browser/chromeos/login/user_manager.h"
84 #include "chrome/browser/chromeos/net/onc_utils.h"
85 #include "chrome/browser/chromeos/system/syslogs_provider.h"
86 #include "chromeos/dbus/dbus_thread_manager.h"
87 #include "chromeos/dbus/debug_daemon_client.h"
88 #include "chromeos/network/onc/onc_certificate_importer_impl.h"
89 #include "chromeos/network/onc/onc_utils.h"
90 #endif
91 #if defined(OS_WIN)
92 #include "chrome/browser/net/service_providers_win.h"
93 #endif
95 using base::PassPlatformFile;
96 using base::PlatformFile;
97 using base::PlatformFileError;
98 using base::StringValue;
99 using content::BrowserThread;
100 using content::WebContents;
101 using content::WebUIMessageHandler;
103 namespace {
105 // Delay between when an event occurs and when it is passed to the Javascript
106 // page. All events that occur during this period are grouped together and
107 // sent to the page at once, which reduces context switching and CPU usage.
108 const int kNetLogEventDelayMilliseconds = 100;
110 // Returns the HostCache for |context|'s primary HostResolver, or NULL if
111 // there is none.
112 net::HostCache* GetHostResolverCache(net::URLRequestContext* context) {
113 return context->host_resolver()->GetHostCache();
116 std::string HashesToBase64String(const net::HashValueVector& hashes) {
117 std::string str;
118 for (size_t i = 0; i != hashes.size(); ++i) {
119 if (i != 0)
120 str += ",";
121 str += hashes[i].ToString();
123 return str;
126 bool Base64StringToHashes(const std::string& hashes_str,
127 net::HashValueVector* hashes) {
128 hashes->clear();
129 std::vector<std::string> vector_hash_str;
130 base::SplitString(hashes_str, ',', &vector_hash_str);
132 for (size_t i = 0; i != vector_hash_str.size(); ++i) {
133 std::string hash_str;
134 base::RemoveChars(vector_hash_str[i], " \t\r\n", &hash_str);
135 net::HashValue hash;
136 // Skip past unrecognized hash algos
137 // But return false on malformatted input
138 if (hash_str.empty())
139 return false;
140 if (hash_str.compare(0, 5, "sha1/") != 0 &&
141 hash_str.compare(0, 7, "sha256/") != 0) {
142 continue;
144 if (!hash.FromString(hash_str))
145 return false;
146 hashes->push_back(hash);
148 return true;
151 // Returns a Value representing the state of a pre-existing URLRequest when
152 // net-internals was opened.
153 base::Value* GetRequestStateAsValue(const net::URLRequest* request,
154 net::NetLog::LogLevel log_level) {
155 return request->GetStateAsValue();
158 // Returns true if |request1| was created before |request2|.
159 bool RequestCreatedBefore(const net::URLRequest* request1,
160 const net::URLRequest* request2) {
161 return request1->creation_time() < request2->creation_time();
164 // Returns the disk cache backend for |context| if there is one, or NULL.
165 disk_cache::Backend* GetDiskCacheBackend(net::URLRequestContext* context) {
166 if (!context->http_transaction_factory())
167 return NULL;
169 net::HttpCache* http_cache = context->http_transaction_factory()->GetCache();
170 if (!http_cache)
171 return NULL;
173 return http_cache->GetCurrentBackend();
176 // Returns the http network session for |context| if there is one.
177 // Otherwise, returns NULL.
178 net::HttpNetworkSession* GetHttpNetworkSession(
179 net::URLRequestContext* context) {
180 if (!context->http_transaction_factory())
181 return NULL;
183 return context->http_transaction_factory()->GetSession();
186 base::Value* ExperimentToValue(const ConnectionTester::Experiment& experiment) {
187 base::DictionaryValue* dict = new base::DictionaryValue();
189 if (experiment.url.is_valid())
190 dict->SetString("url", experiment.url.spec());
192 dict->SetString("proxy_settings_experiment",
193 ConnectionTester::ProxySettingsExperimentDescription(
194 experiment.proxy_settings_experiment));
195 dict->SetString("host_resolver_experiment",
196 ConnectionTester::HostResolverExperimentDescription(
197 experiment.host_resolver_experiment));
198 return dict;
201 content::WebUIDataSource* CreateNetInternalsHTMLSource() {
202 content::WebUIDataSource* source =
203 content::WebUIDataSource::Create(chrome::kChromeUINetInternalsHost);
205 source->SetDefaultResource(IDR_NET_INTERNALS_INDEX_HTML);
206 source->AddResourcePath("index.js", IDR_NET_INTERNALS_INDEX_JS);
207 source->SetJsonPath("strings.js");
208 return source;
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.
214 // Use case:
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), ...),
219 // false);
220 class DebugLogFileHelper {
221 public:
222 typedef base::Callback<void(PassPlatformFile pass_platform_file,
223 bool created,
224 PlatformFileError error,
225 const base::FilePath& file_path)>
226 DebugLogFileCallback;
228 DebugLogFileHelper()
229 : file_handle_(base::kInvalidPlatformFileValue),
230 created_(false),
231 error_(base::PLATFORM_FILE_OK) {
234 ~DebugLogFileHelper() {
237 void DoWork(const base::FilePath& fileshelf) {
238 const base::FilePath::CharType kLogFileName[] =
239 FILE_PATH_LITERAL("debug-log.tgz");
241 file_path_ = fileshelf.Append(kLogFileName);
242 file_path_ = logging::GenerateTimestampedName(file_path_,
243 base::Time::Now());
245 int flags =
246 base::PLATFORM_FILE_CREATE_ALWAYS |
247 base::PLATFORM_FILE_WRITE;
248 file_handle_ = base::CreatePlatformFile(file_path_, flags,
249 &created_, &error_);
252 void Reply(const DebugLogFileCallback& callback) {
253 DCHECK(!callback.is_null());
254 callback.Run(PassPlatformFile(&file_handle_), created_, error_, file_path_);
257 private:
258 PlatformFile file_handle_;
259 bool created_;
260 PlatformFileError error_;
261 base::FilePath file_path_;
263 DISALLOW_COPY_AND_ASSIGN(DebugLogFileHelper);
266 // Following functions are used for getting debug logs. Logs are
267 // fetched from /var/log/* and put on the fileshelf.
269 // Called once StoreDebugLogs is complete. Takes two parameters:
270 // - log_path: where the log file was saved in the case of success;
271 // - succeeded: was the log file saved successfully.
272 typedef base::Callback<void(const base::FilePath& log_path,
273 bool succeded)> StoreDebugLogsCallback;
275 // Closes file handle, so, should be called on the WorkerPool thread.
276 void CloseDebugLogFile(PassPlatformFile pass_platform_file) {
277 base::ClosePlatformFile(pass_platform_file.ReleaseValue());
280 // Closes file handle and deletes debug log file, so, should be called
281 // on the WorkerPool thread.
282 void CloseAndDeleteDebugLogFile(PassPlatformFile pass_platform_file,
283 const base::FilePath& file_path) {
284 CloseDebugLogFile(pass_platform_file);
285 base::DeleteFile(file_path, false);
288 // Called upon completion of |WriteDebugLogToFile|. Closes file
289 // descriptor, deletes log file in the case of failure and calls
290 // |callback|.
291 void WriteDebugLogToFileCompleted(const StoreDebugLogsCallback& callback,
292 PassPlatformFile pass_platform_file,
293 const base::FilePath& file_path,
294 bool succeeded) {
295 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
296 if (!succeeded) {
297 bool posted = base::WorkerPool::PostTaskAndReply(FROM_HERE,
298 base::Bind(&CloseAndDeleteDebugLogFile, pass_platform_file, file_path),
299 base::Bind(callback, file_path, false), false);
300 DCHECK(posted);
301 return;
303 bool posted = base::WorkerPool::PostTaskAndReply(FROM_HERE,
304 base::Bind(&CloseDebugLogFile, pass_platform_file),
305 base::Bind(callback, file_path, true), false);
306 DCHECK(posted);
309 // Stores into |file_path| debug logs in the .tgz format. Calls
310 // |callback| upon completion.
311 void WriteDebugLogToFile(const StoreDebugLogsCallback& callback,
312 PassPlatformFile pass_platform_file,
313 bool created,
314 PlatformFileError error,
315 const base::FilePath& file_path) {
316 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
317 if (!created) {
318 LOG(ERROR) <<
319 "Can't create debug log file: " << file_path.AsUTF8Unsafe() << ", " <<
320 "error: " << error;
321 bool posted = base::WorkerPool::PostTaskAndReply(FROM_HERE,
322 base::Bind(&CloseDebugLogFile, pass_platform_file),
323 base::Bind(callback, file_path, false), false);
324 DCHECK(posted);
325 return;
327 PlatformFile platform_file = pass_platform_file.ReleaseValue();
328 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->GetDebugLogs(
329 platform_file,
330 base::Bind(&WriteDebugLogToFileCompleted,
331 callback, PassPlatformFile(&platform_file), file_path));
334 // Stores debug logs in the .tgz archive on the |fileshelf|. The file
335 // is created on the worker pool, then writing to it is triggered from
336 // the UI thread, and finally it is closed (on success) or deleted (on
337 // failure) on the worker pool, prior to calling |callback|.
338 void StoreDebugLogs(const base::FilePath& fileshelf,
339 const StoreDebugLogsCallback& callback) {
340 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
341 DCHECK(!callback.is_null());
342 DebugLogFileHelper* helper = new DebugLogFileHelper();
343 bool posted = base::WorkerPool::PostTaskAndReply(FROM_HERE,
344 base::Bind(&DebugLogFileHelper::DoWork,
345 base::Unretained(helper), fileshelf),
346 base::Bind(&DebugLogFileHelper::Reply, base::Owned(helper),
347 base::Bind(&WriteDebugLogToFile, callback)), false);
348 DCHECK(posted);
350 #endif // defined(OS_CHROMEOS)
352 // This class receives javascript messages from the renderer.
353 // Note that the WebUI infrastructure runs on the UI thread, therefore all of
354 // this class's methods are expected to run on the UI thread.
356 // Since the network code we want to run lives on the IO thread, we proxy
357 // almost everything over to NetInternalsMessageHandler::IOThreadImpl, which
358 // runs on the IO thread.
360 // TODO(eroman): Can we start on the IO thread to begin with?
361 class NetInternalsMessageHandler
362 : public WebUIMessageHandler,
363 public base::SupportsWeakPtr<NetInternalsMessageHandler> {
364 public:
365 NetInternalsMessageHandler();
366 virtual ~NetInternalsMessageHandler();
368 // WebUIMessageHandler implementation.
369 virtual void RegisterMessages() OVERRIDE;
371 // Calls g_browser.receive in the renderer, passing in |command| and |arg|.
372 // Takes ownership of |arg|. If the renderer is displaying a log file, the
373 // message will be ignored.
374 void SendJavascriptCommand(const std::string& command, base::Value* arg);
376 // Javascript message handlers.
377 void OnRendererReady(const base::ListValue* list);
378 void OnClearBrowserCache(const base::ListValue* list);
379 void OnGetPrerenderInfo(const base::ListValue* list);
380 void OnGetHistoricNetworkStats(const base::ListValue* list);
381 void OnGetExtensionInfo(const base::ListValue* list);
382 #if defined(OS_CHROMEOS)
383 void OnRefreshSystemLogs(const base::ListValue* list);
384 void OnGetSystemLog(const base::ListValue* list);
385 void OnImportONCFile(const base::ListValue* list);
386 void OnStoreDebugLogs(const base::ListValue* list);
387 void OnStoreDebugLogsCompleted(const base::FilePath& log_path,
388 bool succeeded);
389 void OnSetNetworkDebugMode(const base::ListValue* list);
390 void OnSetNetworkDebugModeCompleted(const std::string& subsystem,
391 bool succeeded);
392 #endif
394 private:
395 class IOThreadImpl;
397 #if defined(OS_CHROMEOS)
398 // Class that is used for getting network related ChromeOS logs.
399 // Logs are fetched from ChromeOS libcros on user request, and only when we
400 // don't yet have a copy of logs. If a copy is present, we send back data from
401 // it, else we save request and answer to it when we get logs from libcros.
402 // If needed, we also send request for system logs to libcros.
403 // Logs refresh has to be done explicitly, by deleting old logs and then
404 // loading them again.
405 class SystemLogsGetter {
406 public:
407 SystemLogsGetter(NetInternalsMessageHandler* handler,
408 chromeos::system::SyslogsProvider* syslogs_provider);
409 ~SystemLogsGetter();
411 // Deletes logs copy we currently have, and resets logs_requested and
412 // logs_received flags.
413 void DeleteSystemLogs();
414 // Starts log fetching. If logs copy is present, requested logs are sent
415 // back.
416 // If syslogs load request hasn't been sent to libcros yet, we do that now,
417 // and postpone sending response.
418 // Request data is specified by args:
419 // $1 : key of the log we are interested in.
420 // $2 : string used to identify request.
421 void RequestSystemLog(const base::ListValue* args);
422 // Requests logs from libcros, but only if we don't have a copy.
423 void LoadSystemLogs();
424 // Processes callback from libcros containing system logs. Postponed
425 // request responses are sent.
426 void OnSystemLogsLoaded(chromeos::system::LogDictionaryType* sys_info,
427 std::string* ignored_content);
429 private:
430 // Struct we save postponed log request in.
431 struct SystemLogRequest {
432 std::string log_key;
433 std::string cell_id;
436 // Processes request.
437 void SendLogs(const SystemLogRequest& request);
439 NetInternalsMessageHandler* handler_;
440 chromeos::system::SyslogsProvider* syslogs_provider_;
441 // List of postponed requests.
442 std::list<SystemLogRequest> requests_;
443 scoped_ptr<chromeos::system::LogDictionaryType> logs_;
444 bool logs_received_;
445 bool logs_requested_;
446 CancelableTaskTracker tracker_;
447 // Libcros request task ID.
448 CancelableTaskTracker::TaskId syslogs_task_id_;
450 #endif // defined(OS_CHROMEOS)
452 // This is the "real" message handler, which lives on the IO thread.
453 scoped_refptr<IOThreadImpl> proxy_;
455 base::WeakPtr<prerender::PrerenderManager> prerender_manager_;
457 #if defined(OS_CHROMEOS)
458 // Class that handles getting and filtering system logs.
459 scoped_ptr<SystemLogsGetter> syslogs_getter_;
460 #endif
462 DISALLOW_COPY_AND_ASSIGN(NetInternalsMessageHandler);
465 // This class is the "real" message handler. It is allocated and destroyed on
466 // the UI thread. With the exception of OnAddEntry, OnWebUIDeleted, and
467 // SendJavascriptCommand, its methods are all expected to be called from the IO
468 // thread. OnAddEntry and SendJavascriptCommand can be called from any thread,
469 // and OnWebUIDeleted can only be called from the UI thread.
470 class NetInternalsMessageHandler::IOThreadImpl
471 : public base::RefCountedThreadSafe<
472 NetInternalsMessageHandler::IOThreadImpl,
473 BrowserThread::DeleteOnUIThread>,
474 public net::NetLog::ThreadSafeObserver,
475 public ConnectionTester::Delegate {
476 public:
477 // Type for methods that can be used as MessageHandler callbacks.
478 typedef void (IOThreadImpl::*MessageHandler)(const base::ListValue*);
480 // Creates a proxy for |handler| that will live on the IO thread.
481 // |handler| is a weak pointer, since it is possible for the
482 // WebUIMessageHandler to be deleted on the UI thread while we were executing
483 // on the IO thread. |io_thread| is the global IOThread (it is passed in as
484 // an argument since we need to grab it from the UI thread).
485 IOThreadImpl(
486 const base::WeakPtr<NetInternalsMessageHandler>& handler,
487 IOThread* io_thread,
488 net::URLRequestContextGetter* main_context_getter);
490 // Called on UI thread just after creation, to add a ContextGetter to
491 // |context_getters_|.
492 void AddRequestContextGetter(net::URLRequestContextGetter* context_getter);
494 // Helper method to enable a callback that will be executed on the IO thread.
495 static void CallbackHelper(MessageHandler method,
496 scoped_refptr<IOThreadImpl> io_thread,
497 const base::ListValue* list);
499 // Called once the WebUI has been deleted (i.e. renderer went away), on the
500 // IO thread.
501 void Detach();
503 // Called when the WebUI is deleted. Prevents calling Javascript functions
504 // afterwards. Called on UI thread.
505 void OnWebUIDeleted();
507 //--------------------------------
508 // Javascript message handlers:
509 //--------------------------------
511 void OnRendererReady(const base::ListValue* list);
513 void OnGetProxySettings(const base::ListValue* list);
514 void OnReloadProxySettings(const base::ListValue* list);
515 void OnGetBadProxies(const base::ListValue* list);
516 void OnClearBadProxies(const base::ListValue* list);
517 void OnGetHostResolverInfo(const base::ListValue* list);
518 void OnClearHostResolverCache(const base::ListValue* list);
519 void OnEnableIPv6(const base::ListValue* list);
520 void OnStartConnectionTests(const base::ListValue* list);
521 void OnHSTSQuery(const base::ListValue* list);
522 void OnHSTSAdd(const base::ListValue* list);
523 void OnHSTSDelete(const base::ListValue* list);
524 void OnGetHttpCacheInfo(const base::ListValue* list);
525 void OnGetSocketPoolInfo(const base::ListValue* list);
526 void OnGetSessionNetworkStats(const base::ListValue* list);
527 void OnCloseIdleSockets(const base::ListValue* list);
528 void OnFlushSocketPools(const base::ListValue* list);
529 void OnGetSpdySessionInfo(const base::ListValue* list);
530 void OnGetSpdyStatus(const base::ListValue* list);
531 void OnGetSpdyAlternateProtocolMappings(const base::ListValue* list);
532 void OnGetQuicInfo(const base::ListValue* list);
533 #if defined(OS_WIN)
534 void OnGetServiceProviders(const base::ListValue* list);
535 #endif
536 void OnGetHttpPipeliningStatus(const base::ListValue* list);
537 void OnSetLogLevel(const base::ListValue* list);
539 // ChromeNetLog::ThreadSafeObserver implementation:
540 virtual void OnAddEntry(const net::NetLog::Entry& entry) OVERRIDE;
542 // ConnectionTester::Delegate implementation:
543 virtual void OnStartConnectionTestSuite() OVERRIDE;
544 virtual void OnStartConnectionTestExperiment(
545 const ConnectionTester::Experiment& experiment) OVERRIDE;
546 virtual void OnCompletedConnectionTestExperiment(
547 const ConnectionTester::Experiment& experiment,
548 int result) OVERRIDE;
549 virtual void OnCompletedConnectionTestSuite() OVERRIDE;
551 // Helper that calls g_browser.receive in the renderer, passing in |command|
552 // and |arg|. Takes ownership of |arg|. If the renderer is displaying a log
553 // file, the message will be ignored. Note that this can be called from any
554 // thread.
555 void SendJavascriptCommand(const std::string& command, base::Value* arg);
557 private:
558 friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>;
559 friend class base::DeleteHelper<IOThreadImpl>;
561 typedef std::list<scoped_refptr<net::URLRequestContextGetter> >
562 ContextGetterList;
564 virtual ~IOThreadImpl();
566 // Adds |entry| to the queue of pending log entries to be sent to the page via
567 // Javascript. Must be called on the IO Thread. Also creates a delayed task
568 // that will call PostPendingEntries, if there isn't one already.
569 void AddEntryToQueue(base::Value* entry);
571 // Sends all pending entries to the page via Javascript, and clears the list
572 // of pending entries. Sending multiple entries at once results in a
573 // significant reduction of CPU usage when a lot of events are happening.
574 // Must be called on the IO Thread.
575 void PostPendingEntries();
577 // Adds entries with the states of ongoing URL requests.
578 void PrePopulateEventList();
580 net::URLRequestContext* GetMainContext() {
581 return main_context_getter_->GetURLRequestContext();
584 // Pointer to the UI-thread message handler. Only access this from
585 // the UI thread.
586 base::WeakPtr<NetInternalsMessageHandler> handler_;
588 // The global IOThread, which contains the global NetLog to observer.
589 IOThread* io_thread_;
591 // The main URLRequestContextGetter for the tab's profile.
592 scoped_refptr<net::URLRequestContextGetter> main_context_getter_;
594 // Helper that runs the suite of connection tests.
595 scoped_ptr<ConnectionTester> connection_tester_;
597 // True if the Web UI has been deleted. This is used to prevent calling
598 // Javascript functions after the Web UI is destroyed. On refresh, the
599 // messages can end up being sent to the refreshed page, causing duplicate
600 // or partial entries.
602 // This is only read and written to on the UI thread.
603 bool was_webui_deleted_;
605 // Log entries that have yet to be passed along to Javascript page. Non-NULL
606 // when and only when there is a pending delayed task to call
607 // PostPendingEntries. Read and written to exclusively on the IO Thread.
608 scoped_ptr<base::ListValue> pending_entries_;
610 // Used for getting current status of URLRequests when net-internals is
611 // opened. |main_context_getter_| is automatically added on construction.
612 // Duplicates are allowed.
613 ContextGetterList context_getters_;
615 DISALLOW_COPY_AND_ASSIGN(IOThreadImpl);
618 ////////////////////////////////////////////////////////////////////////////////
620 // NetInternalsMessageHandler
622 ////////////////////////////////////////////////////////////////////////////////
624 NetInternalsMessageHandler::NetInternalsMessageHandler() {}
626 NetInternalsMessageHandler::~NetInternalsMessageHandler() {
627 if (proxy_.get()) {
628 proxy_.get()->OnWebUIDeleted();
629 // Notify the handler on the IO thread that the renderer is gone.
630 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
631 base::Bind(&IOThreadImpl::Detach, proxy_.get()));
635 void NetInternalsMessageHandler::RegisterMessages() {
636 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
638 Profile* profile = Profile::FromWebUI(web_ui());
640 proxy_ = new IOThreadImpl(this->AsWeakPtr(), g_browser_process->io_thread(),
641 profile->GetRequestContext());
642 proxy_->AddRequestContextGetter(profile->GetMediaRequestContext());
643 proxy_->AddRequestContextGetter(profile->GetRequestContextForExtensions());
644 #if defined(OS_CHROMEOS)
645 syslogs_getter_.reset(new SystemLogsGetter(this,
646 chromeos::system::SyslogsProvider::GetInstance()));
647 #endif
649 prerender::PrerenderManager* prerender_manager =
650 prerender::PrerenderManagerFactory::GetForProfile(profile);
651 if (prerender_manager) {
652 prerender_manager_ = prerender_manager->AsWeakPtr();
653 } else {
654 prerender_manager_ = base::WeakPtr<prerender::PrerenderManager>();
657 web_ui()->RegisterMessageCallback(
658 "notifyReady",
659 base::Bind(&NetInternalsMessageHandler::OnRendererReady,
660 base::Unretained(this)));
661 web_ui()->RegisterMessageCallback(
662 "getProxySettings",
663 base::Bind(&IOThreadImpl::CallbackHelper,
664 &IOThreadImpl::OnGetProxySettings, proxy_));
665 web_ui()->RegisterMessageCallback(
666 "reloadProxySettings",
667 base::Bind(&IOThreadImpl::CallbackHelper,
668 &IOThreadImpl::OnReloadProxySettings, proxy_));
669 web_ui()->RegisterMessageCallback(
670 "getBadProxies",
671 base::Bind(&IOThreadImpl::CallbackHelper,
672 &IOThreadImpl::OnGetBadProxies, proxy_));
673 web_ui()->RegisterMessageCallback(
674 "clearBadProxies",
675 base::Bind(&IOThreadImpl::CallbackHelper,
676 &IOThreadImpl::OnClearBadProxies, proxy_));
677 web_ui()->RegisterMessageCallback(
678 "getHostResolverInfo",
679 base::Bind(&IOThreadImpl::CallbackHelper,
680 &IOThreadImpl::OnGetHostResolverInfo, proxy_));
681 web_ui()->RegisterMessageCallback(
682 "clearHostResolverCache",
683 base::Bind(&IOThreadImpl::CallbackHelper,
684 &IOThreadImpl::OnClearHostResolverCache, proxy_));
685 web_ui()->RegisterMessageCallback(
686 "enableIPv6",
687 base::Bind(&IOThreadImpl::CallbackHelper,
688 &IOThreadImpl::OnEnableIPv6, proxy_));
689 web_ui()->RegisterMessageCallback(
690 "startConnectionTests",
691 base::Bind(&IOThreadImpl::CallbackHelper,
692 &IOThreadImpl::OnStartConnectionTests, proxy_));
693 web_ui()->RegisterMessageCallback(
694 "hstsQuery",
695 base::Bind(&IOThreadImpl::CallbackHelper,
696 &IOThreadImpl::OnHSTSQuery, proxy_));
697 web_ui()->RegisterMessageCallback(
698 "hstsAdd",
699 base::Bind(&IOThreadImpl::CallbackHelper,
700 &IOThreadImpl::OnHSTSAdd, proxy_));
701 web_ui()->RegisterMessageCallback(
702 "hstsDelete",
703 base::Bind(&IOThreadImpl::CallbackHelper,
704 &IOThreadImpl::OnHSTSDelete, proxy_));
705 web_ui()->RegisterMessageCallback(
706 "getHttpCacheInfo",
707 base::Bind(&IOThreadImpl::CallbackHelper,
708 &IOThreadImpl::OnGetHttpCacheInfo, proxy_));
709 web_ui()->RegisterMessageCallback(
710 "getSocketPoolInfo",
711 base::Bind(&IOThreadImpl::CallbackHelper,
712 &IOThreadImpl::OnGetSocketPoolInfo, proxy_));
713 web_ui()->RegisterMessageCallback(
714 "getSessionNetworkStats",
715 base::Bind(&IOThreadImpl::CallbackHelper,
716 &IOThreadImpl::OnGetSessionNetworkStats, proxy_));
717 web_ui()->RegisterMessageCallback(
718 "closeIdleSockets",
719 base::Bind(&IOThreadImpl::CallbackHelper,
720 &IOThreadImpl::OnCloseIdleSockets, proxy_));
721 web_ui()->RegisterMessageCallback(
722 "flushSocketPools",
723 base::Bind(&IOThreadImpl::CallbackHelper,
724 &IOThreadImpl::OnFlushSocketPools, proxy_));
725 web_ui()->RegisterMessageCallback(
726 "getSpdySessionInfo",
727 base::Bind(&IOThreadImpl::CallbackHelper,
728 &IOThreadImpl::OnGetSpdySessionInfo, proxy_));
729 web_ui()->RegisterMessageCallback(
730 "getSpdyStatus",
731 base::Bind(&IOThreadImpl::CallbackHelper,
732 &IOThreadImpl::OnGetSpdyStatus, proxy_));
733 web_ui()->RegisterMessageCallback(
734 "getSpdyAlternateProtocolMappings",
735 base::Bind(&IOThreadImpl::CallbackHelper,
736 &IOThreadImpl::OnGetSpdyAlternateProtocolMappings, proxy_));
737 web_ui()->RegisterMessageCallback(
738 "getQuicInfo",
739 base::Bind(&IOThreadImpl::CallbackHelper,
740 &IOThreadImpl::OnGetQuicInfo, proxy_));
741 #if defined(OS_WIN)
742 web_ui()->RegisterMessageCallback(
743 "getServiceProviders",
744 base::Bind(&IOThreadImpl::CallbackHelper,
745 &IOThreadImpl::OnGetServiceProviders, proxy_));
746 #endif
748 web_ui()->RegisterMessageCallback(
749 "getHttpPipeliningStatus",
750 base::Bind(&IOThreadImpl::CallbackHelper,
751 &IOThreadImpl::OnGetHttpPipeliningStatus, proxy_));
752 web_ui()->RegisterMessageCallback(
753 "setLogLevel",
754 base::Bind(&IOThreadImpl::CallbackHelper,
755 &IOThreadImpl::OnSetLogLevel, proxy_));
756 web_ui()->RegisterMessageCallback(
757 "clearBrowserCache",
758 base::Bind(&NetInternalsMessageHandler::OnClearBrowserCache,
759 base::Unretained(this)));
760 web_ui()->RegisterMessageCallback(
761 "getPrerenderInfo",
762 base::Bind(&NetInternalsMessageHandler::OnGetPrerenderInfo,
763 base::Unretained(this)));
764 web_ui()->RegisterMessageCallback(
765 "getHistoricNetworkStats",
766 base::Bind(&NetInternalsMessageHandler::OnGetHistoricNetworkStats,
767 base::Unretained(this)));
768 web_ui()->RegisterMessageCallback(
769 "getExtensionInfo",
770 base::Bind(&NetInternalsMessageHandler::OnGetExtensionInfo,
771 base::Unretained(this)));
772 #if defined(OS_CHROMEOS)
773 web_ui()->RegisterMessageCallback(
774 "refreshSystemLogs",
775 base::Bind(&NetInternalsMessageHandler::OnRefreshSystemLogs,
776 base::Unretained(this)));
777 web_ui()->RegisterMessageCallback(
778 "getSystemLog",
779 base::Bind(&NetInternalsMessageHandler::OnGetSystemLog,
780 base::Unretained(this)));
781 web_ui()->RegisterMessageCallback(
782 "importONCFile",
783 base::Bind(&NetInternalsMessageHandler::OnImportONCFile,
784 base::Unretained(this)));
785 web_ui()->RegisterMessageCallback(
786 "storeDebugLogs",
787 base::Bind(&NetInternalsMessageHandler::OnStoreDebugLogs,
788 base::Unretained(this)));
789 web_ui()->RegisterMessageCallback(
790 "setNetworkDebugMode",
791 base::Bind(&NetInternalsMessageHandler::OnSetNetworkDebugMode,
792 base::Unretained(this)));
793 #endif
796 void NetInternalsMessageHandler::SendJavascriptCommand(
797 const std::string& command,
798 base::Value* arg) {
799 scoped_ptr<base::Value> command_value(new base::StringValue(command));
800 scoped_ptr<base::Value> value(arg);
801 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
802 if (value.get()) {
803 web_ui()->CallJavascriptFunction("g_browser.receive",
804 *command_value.get(),
805 *value.get());
806 } else {
807 web_ui()->CallJavascriptFunction("g_browser.receive",
808 *command_value.get());
812 void NetInternalsMessageHandler::OnRendererReady(const base::ListValue* list) {
813 IOThreadImpl::CallbackHelper(&IOThreadImpl::OnRendererReady, proxy_, list);
816 void NetInternalsMessageHandler::OnClearBrowserCache(
817 const base::ListValue* list) {
818 BrowsingDataRemover* remover = BrowsingDataRemover::CreateForUnboundedRange(
819 Profile::FromWebUI(web_ui()));
820 remover->Remove(BrowsingDataRemover::REMOVE_CACHE,
821 BrowsingDataHelper::UNPROTECTED_WEB);
822 // BrowsingDataRemover deletes itself.
825 void NetInternalsMessageHandler::OnGetPrerenderInfo(
826 const base::ListValue* list) {
827 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
829 base::DictionaryValue* value = NULL;
830 prerender::PrerenderManager* prerender_manager = prerender_manager_.get();
831 if (!prerender_manager) {
832 value = new base::DictionaryValue();
833 value->SetBoolean("enabled", false);
834 value->SetBoolean("omnibox_enabled", false);
835 } else {
836 value = prerender_manager->GetAsValue();
838 SendJavascriptCommand("receivedPrerenderInfo", value);
841 void NetInternalsMessageHandler::OnGetHistoricNetworkStats(
842 const base::ListValue* list) {
843 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
844 base::Value* historic_network_info =
845 ChromeNetworkDelegate::HistoricNetworkStatsInfoToValue();
846 SendJavascriptCommand("receivedHistoricNetworkStats", historic_network_info);
849 void NetInternalsMessageHandler::OnGetExtensionInfo(
850 const base::ListValue* list) {
851 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
852 base::ListValue* extension_list = new base::ListValue();
853 Profile* profile = Profile::FromWebUI(web_ui());
854 extensions::ExtensionSystem* extension_system =
855 extensions::ExtensionSystem::Get(profile);
856 if (extension_system) {
857 ExtensionService* extension_service = extension_system->extension_service();
858 if (extension_service) {
859 scoped_ptr<const extensions::ExtensionSet> extensions(
860 extension_service->GenerateInstalledExtensionsSet());
861 for (extensions::ExtensionSet::const_iterator it = extensions->begin();
862 it != extensions->end(); ++it) {
863 base::DictionaryValue* extension_info = new base::DictionaryValue();
864 bool enabled = extension_service->IsExtensionEnabled((*it)->id());
865 extensions::GetExtensionBasicInfo(it->get(), enabled, extension_info);
866 extension_list->Append(extension_info);
870 SendJavascriptCommand("receivedExtensionInfo", extension_list);
873 #if defined(OS_CHROMEOS)
874 ////////////////////////////////////////////////////////////////////////////////
876 // NetInternalsMessageHandler::SystemLogsGetter
878 ////////////////////////////////////////////////////////////////////////////////
880 NetInternalsMessageHandler::SystemLogsGetter::SystemLogsGetter(
881 NetInternalsMessageHandler* handler,
882 chromeos::system::SyslogsProvider* syslogs_provider)
883 : handler_(handler),
884 syslogs_provider_(syslogs_provider),
885 logs_received_(false),
886 logs_requested_(false) {
887 if (!syslogs_provider_)
888 LOG(ERROR) << "System access library not loaded";
891 NetInternalsMessageHandler::SystemLogsGetter::~SystemLogsGetter() {
892 DeleteSystemLogs();
895 void NetInternalsMessageHandler::SystemLogsGetter::DeleteSystemLogs() {
896 if (syslogs_provider_ && logs_requested_ && !logs_received_) {
897 tracker_.TryCancel(syslogs_task_id_);
899 logs_requested_ = false;
900 logs_received_ = false;
901 logs_.reset();
904 void NetInternalsMessageHandler::SystemLogsGetter::RequestSystemLog(
905 const base::ListValue* args) {
906 if (!logs_requested_) {
907 DCHECK(!logs_received_);
908 LoadSystemLogs();
910 SystemLogRequest log_request;
911 args->GetString(0, &log_request.log_key);
912 args->GetString(1, &log_request.cell_id);
914 if (logs_received_) {
915 SendLogs(log_request);
916 } else {
917 requests_.push_back(log_request);
921 void NetInternalsMessageHandler::SystemLogsGetter::LoadSystemLogs() {
922 if (logs_requested_ || !syslogs_provider_)
923 return;
924 logs_requested_ = true;
925 syslogs_task_id_ = syslogs_provider_->RequestSyslogs(
926 false, // compress logs.
927 chromeos::system::SyslogsProvider::SYSLOGS_NETWORK,
928 base::Bind(
929 &NetInternalsMessageHandler::SystemLogsGetter::OnSystemLogsLoaded,
930 base::Unretained(this)),
931 &tracker_);
934 void NetInternalsMessageHandler::SystemLogsGetter::OnSystemLogsLoaded(
935 chromeos::system::LogDictionaryType* sys_info,
936 std::string* ignored_content) {
937 DCHECK(!ignored_content);
938 logs_.reset(sys_info);
939 logs_received_ = true;
940 for (std::list<SystemLogRequest>::iterator request_it = requests_.begin();
941 request_it != requests_.end();
942 ++request_it) {
943 SendLogs(*request_it);
945 requests_.clear();
948 void NetInternalsMessageHandler::SystemLogsGetter::SendLogs(
949 const SystemLogRequest& request) {
950 base::DictionaryValue* result = new base::DictionaryValue();
951 chromeos::system::LogDictionaryType::iterator log_it =
952 logs_->find(request.log_key);
953 if (log_it != logs_->end()) {
954 if (!log_it->second.empty()) {
955 result->SetString("log", log_it->second);
956 } else {
957 result->SetString("log", "<no relevant lines found>");
959 } else {
960 result->SetString("log", "<invalid log name>");
962 result->SetString("cellId", request.cell_id);
964 handler_->SendJavascriptCommand("getSystemLogCallback", result);
966 #endif // defined(OS_CHROMEOS)
968 ////////////////////////////////////////////////////////////////////////////////
970 // NetInternalsMessageHandler::IOThreadImpl
972 ////////////////////////////////////////////////////////////////////////////////
974 NetInternalsMessageHandler::IOThreadImpl::IOThreadImpl(
975 const base::WeakPtr<NetInternalsMessageHandler>& handler,
976 IOThread* io_thread,
977 net::URLRequestContextGetter* main_context_getter)
978 : handler_(handler),
979 io_thread_(io_thread),
980 main_context_getter_(main_context_getter),
981 was_webui_deleted_(false) {
982 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
983 AddRequestContextGetter(main_context_getter);
986 NetInternalsMessageHandler::IOThreadImpl::~IOThreadImpl() {
987 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
990 void NetInternalsMessageHandler::IOThreadImpl::AddRequestContextGetter(
991 net::URLRequestContextGetter* context_getter) {
992 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
993 context_getters_.push_back(context_getter);
996 void NetInternalsMessageHandler::IOThreadImpl::CallbackHelper(
997 MessageHandler method,
998 scoped_refptr<IOThreadImpl> io_thread,
999 const base::ListValue* list) {
1000 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1002 // We need to make a copy of the value in order to pass it over to the IO
1003 // thread. |list_copy| will be deleted when the task is destroyed. The called
1004 // |method| cannot take ownership of |list_copy|.
1005 base::ListValue* list_copy =
1006 (list && list->GetSize()) ? list->DeepCopy() : NULL;
1008 BrowserThread::PostTask(
1009 BrowserThread::IO, FROM_HERE,
1010 base::Bind(method, io_thread, base::Owned(list_copy)));
1013 void NetInternalsMessageHandler::IOThreadImpl::Detach() {
1014 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1015 // Unregister with network stack to observe events.
1016 if (net_log())
1017 net_log()->RemoveThreadSafeObserver(this);
1019 // Cancel any in-progress connection tests.
1020 connection_tester_.reset();
1023 void NetInternalsMessageHandler::IOThreadImpl::OnWebUIDeleted() {
1024 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1025 was_webui_deleted_ = true;
1028 void NetInternalsMessageHandler::IOThreadImpl::OnRendererReady(
1029 const base::ListValue* list) {
1030 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1032 // If we have any pending entries, go ahead and get rid of them, so they won't
1033 // appear before the REQUEST_ALIVE events we add for currently active
1034 // URLRequests.
1035 PostPendingEntries();
1037 SendJavascriptCommand("receivedConstants", NetInternalsUI::GetConstants());
1039 // Add entries for ongoing URL requests.
1040 PrePopulateEventList();
1042 if (!net_log()) {
1043 // Register with network stack to observe events.
1044 io_thread_->net_log()->AddThreadSafeObserver(this,
1045 net::NetLog::LOG_ALL_BUT_BYTES);
1049 void NetInternalsMessageHandler::IOThreadImpl::OnGetProxySettings(
1050 const base::ListValue* list) {
1051 DCHECK(!list);
1052 net::ProxyService* proxy_service = GetMainContext()->proxy_service();
1054 base::DictionaryValue* dict = new base::DictionaryValue();
1055 if (proxy_service->fetched_config().is_valid())
1056 dict->Set("original", proxy_service->fetched_config().ToValue());
1057 if (proxy_service->config().is_valid())
1058 dict->Set("effective", proxy_service->config().ToValue());
1060 SendJavascriptCommand("receivedProxySettings", dict);
1063 void NetInternalsMessageHandler::IOThreadImpl::OnReloadProxySettings(
1064 const base::ListValue* list) {
1065 DCHECK(!list);
1066 GetMainContext()->proxy_service()->ForceReloadProxyConfig();
1068 // Cause the renderer to be notified of the new values.
1069 OnGetProxySettings(NULL);
1072 void NetInternalsMessageHandler::IOThreadImpl::OnGetBadProxies(
1073 const base::ListValue* list) {
1074 DCHECK(!list);
1076 const net::ProxyRetryInfoMap& bad_proxies_map =
1077 GetMainContext()->proxy_service()->proxy_retry_info();
1079 base::ListValue* dict_list = new base::ListValue();
1081 for (net::ProxyRetryInfoMap::const_iterator it = bad_proxies_map.begin();
1082 it != bad_proxies_map.end(); ++it) {
1083 const std::string& proxy_uri = it->first;
1084 const net::ProxyRetryInfo& retry_info = it->second;
1086 base::DictionaryValue* dict = new base::DictionaryValue();
1087 dict->SetString("proxy_uri", proxy_uri);
1088 dict->SetString("bad_until",
1089 net::NetLog::TickCountToString(retry_info.bad_until));
1091 dict_list->Append(dict);
1094 SendJavascriptCommand("receivedBadProxies", dict_list);
1097 void NetInternalsMessageHandler::IOThreadImpl::OnClearBadProxies(
1098 const base::ListValue* list) {
1099 DCHECK(!list);
1100 GetMainContext()->proxy_service()->ClearBadProxiesCache();
1102 // Cause the renderer to be notified of the new values.
1103 OnGetBadProxies(NULL);
1106 void NetInternalsMessageHandler::IOThreadImpl::OnGetHostResolverInfo(
1107 const base::ListValue* list) {
1108 DCHECK(!list);
1109 net::URLRequestContext* context = GetMainContext();
1110 net::HostCache* cache = GetHostResolverCache(context);
1112 if (!cache) {
1113 SendJavascriptCommand("receivedHostResolverInfo", NULL);
1114 return;
1117 base::DictionaryValue* dict = new base::DictionaryValue();
1119 base::Value* dns_config = context->host_resolver()->GetDnsConfigAsValue();
1120 if (dns_config)
1121 dict->Set("dns_config", dns_config);
1123 dict->SetInteger(
1124 "default_address_family",
1125 static_cast<int>(context->host_resolver()->GetDefaultAddressFamily()));
1127 base::DictionaryValue* cache_info_dict = new base::DictionaryValue();
1129 cache_info_dict->SetInteger(
1130 "capacity",
1131 static_cast<int>(cache->max_entries()));
1133 base::ListValue* entry_list = new base::ListValue();
1135 net::HostCache::EntryMap::Iterator it(cache->entries());
1136 for (; it.HasNext(); it.Advance()) {
1137 const net::HostCache::Key& key = it.key();
1138 const net::HostCache::Entry& entry = it.value();
1140 base::DictionaryValue* entry_dict = new base::DictionaryValue();
1142 entry_dict->SetString("hostname", key.hostname);
1143 entry_dict->SetInteger("address_family",
1144 static_cast<int>(key.address_family));
1145 entry_dict->SetString("expiration",
1146 net::NetLog::TickCountToString(it.expiration()));
1148 if (entry.error != net::OK) {
1149 entry_dict->SetInteger("error", entry.error);
1150 } else {
1151 // Append all of the resolved addresses.
1152 base::ListValue* address_list = new base::ListValue();
1153 for (size_t i = 0; i < entry.addrlist.size(); ++i) {
1154 address_list->AppendString(entry.addrlist[i].ToStringWithoutPort());
1156 entry_dict->Set("addresses", address_list);
1159 entry_list->Append(entry_dict);
1162 cache_info_dict->Set("entries", entry_list);
1163 dict->Set("cache", cache_info_dict);
1165 SendJavascriptCommand("receivedHostResolverInfo", dict);
1168 void NetInternalsMessageHandler::IOThreadImpl::OnClearHostResolverCache(
1169 const base::ListValue* list) {
1170 DCHECK(!list);
1171 net::HostCache* cache = GetHostResolverCache(GetMainContext());
1173 if (cache)
1174 cache->clear();
1176 // Cause the renderer to be notified of the new values.
1177 OnGetHostResolverInfo(NULL);
1180 void NetInternalsMessageHandler::IOThreadImpl::OnEnableIPv6(
1181 const base::ListValue* list) {
1182 DCHECK(!list);
1183 net::HostResolver* host_resolver = GetMainContext()->host_resolver();
1185 host_resolver->SetDefaultAddressFamily(net::ADDRESS_FAMILY_UNSPECIFIED);
1187 // Cause the renderer to be notified of the new value.
1188 OnGetHostResolverInfo(NULL);
1191 void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTests(
1192 const base::ListValue* list) {
1193 // |value| should be: [<URL to test>].
1194 base::string16 url_str;
1195 CHECK(list->GetString(0, &url_str));
1197 // Try to fix-up the user provided URL into something valid.
1198 // For example, turn "www.google.com" into "http://www.google.com".
1199 GURL url(URLFixerUpper::FixupURL(base::UTF16ToUTF8(url_str), std::string()));
1201 connection_tester_.reset(new ConnectionTester(
1202 this,
1203 io_thread_->globals()->proxy_script_fetcher_context.get(),
1204 net_log()));
1205 connection_tester_->RunAllTests(url);
1208 void NetInternalsMessageHandler::IOThreadImpl::OnHSTSQuery(
1209 const base::ListValue* list) {
1210 // |list| should be: [<domain to query>].
1211 std::string domain;
1212 CHECK(list->GetString(0, &domain));
1213 base::DictionaryValue* result = new base::DictionaryValue();
1215 if (!IsStringASCII(domain)) {
1216 result->SetString("error", "non-ASCII domain name");
1217 } else {
1218 net::TransportSecurityState* transport_security_state =
1219 GetMainContext()->transport_security_state();
1220 if (!transport_security_state) {
1221 result->SetString("error", "no TransportSecurityState active");
1222 } else {
1223 net::TransportSecurityState::DomainState state;
1224 const bool found = transport_security_state->GetDomainState(
1225 domain, true, &state);
1227 result->SetBoolean("result", found);
1228 if (found) {
1229 result->SetInteger("mode", static_cast<int>(state.upgrade_mode));
1230 result->SetBoolean("sts_subdomains", state.sts_include_subdomains);
1231 result->SetBoolean("pkp_subdomains", state.pkp_include_subdomains);
1232 result->SetDouble("sts_observed", state.sts_observed.ToDoubleT());
1233 result->SetDouble("pkp_observed", state.pkp_observed.ToDoubleT());
1234 result->SetString("domain", state.domain);
1235 result->SetDouble("expiry", state.upgrade_expiry.ToDoubleT());
1236 result->SetDouble("dynamic_spki_hashes_expiry",
1237 state.dynamic_spki_hashes_expiry.ToDoubleT());
1239 result->SetString("static_spki_hashes",
1240 HashesToBase64String(state.static_spki_hashes));
1241 result->SetString("dynamic_spki_hashes",
1242 HashesToBase64String(state.dynamic_spki_hashes));
1247 SendJavascriptCommand("receivedHSTSResult", result);
1250 void NetInternalsMessageHandler::IOThreadImpl::OnHSTSAdd(
1251 const base::ListValue* list) {
1252 // |list| should be: [<domain to query>, <STS include subdomains>, <PKP
1253 // include subdomains>, <key pins>].
1254 std::string domain;
1255 CHECK(list->GetString(0, &domain));
1256 if (!IsStringASCII(domain)) {
1257 // Silently fail. The user will get a helpful error if they query for the
1258 // name.
1259 return;
1261 bool sts_include_subdomains;
1262 CHECK(list->GetBoolean(1, &sts_include_subdomains));
1263 bool pkp_include_subdomains;
1264 CHECK(list->GetBoolean(2, &pkp_include_subdomains));
1265 std::string hashes_str;
1266 CHECK(list->GetString(3, &hashes_str));
1268 net::TransportSecurityState* transport_security_state =
1269 GetMainContext()->transport_security_state();
1270 if (!transport_security_state)
1271 return;
1273 base::Time expiry = base::Time::Now() + base::TimeDelta::FromDays(1000);
1274 net::HashValueVector hashes;
1275 if (!hashes_str.empty()) {
1276 if (!Base64StringToHashes(hashes_str, &hashes))
1277 return;
1280 transport_security_state->AddHSTS(domain, expiry, sts_include_subdomains);
1281 transport_security_state->AddHPKP(domain, expiry, pkp_include_subdomains,
1282 hashes);
1285 void NetInternalsMessageHandler::IOThreadImpl::OnHSTSDelete(
1286 const base::ListValue* list) {
1287 // |list| should be: [<domain to query>].
1288 std::string domain;
1289 CHECK(list->GetString(0, &domain));
1290 if (!IsStringASCII(domain)) {
1291 // There cannot be a unicode entry in the HSTS set.
1292 return;
1294 net::TransportSecurityState* transport_security_state =
1295 GetMainContext()->transport_security_state();
1296 if (!transport_security_state)
1297 return;
1299 transport_security_state->DeleteDynamicDataForHost(domain);
1302 void NetInternalsMessageHandler::IOThreadImpl::OnGetHttpCacheInfo(
1303 const base::ListValue* list) {
1304 DCHECK(!list);
1305 base::DictionaryValue* info_dict = new base::DictionaryValue();
1306 base::DictionaryValue* stats_dict = new base::DictionaryValue();
1308 disk_cache::Backend* disk_cache = GetDiskCacheBackend(GetMainContext());
1310 if (disk_cache) {
1311 // Extract the statistics key/value pairs from the backend.
1312 std::vector<std::pair<std::string, std::string> > stats;
1313 disk_cache->GetStats(&stats);
1314 for (size_t i = 0; i < stats.size(); ++i) {
1315 stats_dict->SetStringWithoutPathExpansion(
1316 stats[i].first, stats[i].second);
1320 info_dict->Set("stats", stats_dict);
1322 SendJavascriptCommand("receivedHttpCacheInfo", info_dict);
1325 void NetInternalsMessageHandler::IOThreadImpl::OnGetSocketPoolInfo(
1326 const base::ListValue* list) {
1327 DCHECK(!list);
1328 net::HttpNetworkSession* http_network_session =
1329 GetHttpNetworkSession(GetMainContext());
1331 base::Value* socket_pool_info = NULL;
1332 if (http_network_session)
1333 socket_pool_info = http_network_session->SocketPoolInfoToValue();
1335 SendJavascriptCommand("receivedSocketPoolInfo", socket_pool_info);
1338 void NetInternalsMessageHandler::IOThreadImpl::OnGetSessionNetworkStats(
1339 const base::ListValue* list) {
1340 DCHECK(!list);
1341 net::HttpNetworkSession* http_network_session =
1342 GetHttpNetworkSession(main_context_getter_->GetURLRequestContext());
1344 base::Value* network_info = NULL;
1345 if (http_network_session) {
1346 ChromeNetworkDelegate* net_delegate =
1347 static_cast<ChromeNetworkDelegate*>(
1348 http_network_session->network_delegate());
1349 if (net_delegate) {
1350 network_info = net_delegate->SessionNetworkStatsInfoToValue();
1353 SendJavascriptCommand("receivedSessionNetworkStats", network_info);
1356 void NetInternalsMessageHandler::IOThreadImpl::OnFlushSocketPools(
1357 const base::ListValue* list) {
1358 DCHECK(!list);
1359 net::HttpNetworkSession* http_network_session =
1360 GetHttpNetworkSession(GetMainContext());
1362 if (http_network_session)
1363 http_network_session->CloseAllConnections();
1366 void NetInternalsMessageHandler::IOThreadImpl::OnCloseIdleSockets(
1367 const base::ListValue* list) {
1368 DCHECK(!list);
1369 net::HttpNetworkSession* http_network_session =
1370 GetHttpNetworkSession(GetMainContext());
1372 if (http_network_session)
1373 http_network_session->CloseIdleConnections();
1376 void NetInternalsMessageHandler::IOThreadImpl::OnGetSpdySessionInfo(
1377 const base::ListValue* list) {
1378 DCHECK(!list);
1379 net::HttpNetworkSession* http_network_session =
1380 GetHttpNetworkSession(GetMainContext());
1382 base::Value* spdy_info = http_network_session ?
1383 http_network_session->SpdySessionPoolInfoToValue() : NULL;
1384 SendJavascriptCommand("receivedSpdySessionInfo", spdy_info);
1387 void NetInternalsMessageHandler::IOThreadImpl::OnGetSpdyStatus(
1388 const base::ListValue* list) {
1389 DCHECK(!list);
1390 base::DictionaryValue* status_dict = new base::DictionaryValue();
1392 status_dict->Set("spdy_enabled",
1393 base::Value::CreateBooleanValue(
1394 net::HttpStreamFactory::spdy_enabled()));
1395 status_dict->Set("use_alternate_protocols",
1396 base::Value::CreateBooleanValue(
1397 net::HttpStreamFactory::use_alternate_protocols()));
1398 status_dict->Set("force_spdy_over_ssl",
1399 base::Value::CreateBooleanValue(
1400 net::HttpStreamFactory::force_spdy_over_ssl()));
1401 status_dict->Set("force_spdy_always",
1402 base::Value::CreateBooleanValue(
1403 net::HttpStreamFactory::force_spdy_always()));
1405 // The next_protos may not be specified for certain configurations of SPDY.
1406 std::string next_protos_string;
1407 if (net::HttpStreamFactory::has_next_protos()) {
1408 next_protos_string = JoinString(net::HttpStreamFactory::next_protos(), ',');
1410 status_dict->SetString("next_protos", next_protos_string);
1412 SendJavascriptCommand("receivedSpdyStatus", status_dict);
1415 void
1416 NetInternalsMessageHandler::IOThreadImpl::OnGetSpdyAlternateProtocolMappings(
1417 const base::ListValue* list) {
1418 DCHECK(!list);
1419 base::ListValue* dict_list = new base::ListValue();
1421 const net::HttpServerProperties& http_server_properties =
1422 *GetMainContext()->http_server_properties();
1424 const net::AlternateProtocolMap& map =
1425 http_server_properties.alternate_protocol_map();
1427 for (net::AlternateProtocolMap::const_iterator it = map.begin();
1428 it != map.end(); ++it) {
1429 base::DictionaryValue* dict = new base::DictionaryValue();
1430 dict->SetString("host_port_pair", it->first.ToString());
1431 dict->SetString("alternate_protocol", it->second.ToString());
1432 dict_list->Append(dict);
1435 SendJavascriptCommand("receivedSpdyAlternateProtocolMappings", dict_list);
1438 void NetInternalsMessageHandler::IOThreadImpl::OnGetQuicInfo(
1439 const base::ListValue* list) {
1440 DCHECK(!list);
1441 net::HttpNetworkSession* http_network_session =
1442 GetHttpNetworkSession(GetMainContext());
1444 base::Value* quic_info = http_network_session ?
1445 http_network_session->QuicInfoToValue() : NULL;
1446 SendJavascriptCommand("receivedQuicInfo", quic_info);
1449 #if defined(OS_WIN)
1450 void NetInternalsMessageHandler::IOThreadImpl::OnGetServiceProviders(
1451 const base::ListValue* list) {
1452 DCHECK(!list);
1454 base::DictionaryValue* service_providers = new base::DictionaryValue();
1456 WinsockLayeredServiceProviderList layered_providers;
1457 GetWinsockLayeredServiceProviders(&layered_providers);
1458 base::ListValue* layered_provider_list = new base::ListValue();
1459 for (size_t i = 0; i < layered_providers.size(); ++i) {
1460 base::DictionaryValue* service_dict = new base::DictionaryValue();
1461 service_dict->SetString("name", layered_providers[i].name);
1462 service_dict->SetInteger("version", layered_providers[i].version);
1463 service_dict->SetInteger("chain_length", layered_providers[i].chain_length);
1464 service_dict->SetInteger("socket_type", layered_providers[i].socket_type);
1465 service_dict->SetInteger("socket_protocol",
1466 layered_providers[i].socket_protocol);
1467 service_dict->SetString("path", layered_providers[i].path);
1469 layered_provider_list->Append(service_dict);
1471 service_providers->Set("service_providers", layered_provider_list);
1473 WinsockNamespaceProviderList namespace_providers;
1474 GetWinsockNamespaceProviders(&namespace_providers);
1475 base::ListValue* namespace_list = new base::ListValue;
1476 for (size_t i = 0; i < namespace_providers.size(); ++i) {
1477 base::DictionaryValue* namespace_dict = new base::DictionaryValue();
1478 namespace_dict->SetString("name", namespace_providers[i].name);
1479 namespace_dict->SetBoolean("active", namespace_providers[i].active);
1480 namespace_dict->SetInteger("version", namespace_providers[i].version);
1481 namespace_dict->SetInteger("type", namespace_providers[i].type);
1483 namespace_list->Append(namespace_dict);
1485 service_providers->Set("namespace_providers", namespace_list);
1487 SendJavascriptCommand("receivedServiceProviders", service_providers);
1489 #endif
1491 #if defined(OS_CHROMEOS)
1492 void NetInternalsMessageHandler::OnRefreshSystemLogs(
1493 const base::ListValue* list) {
1494 DCHECK(!list);
1495 DCHECK(syslogs_getter_.get());
1496 syslogs_getter_->DeleteSystemLogs();
1497 syslogs_getter_->LoadSystemLogs();
1500 void NetInternalsMessageHandler::OnGetSystemLog(
1501 const base::ListValue* list) {
1502 DCHECK(syslogs_getter_.get());
1503 syslogs_getter_->RequestSystemLog(list);
1506 void NetInternalsMessageHandler::OnImportONCFile(
1507 const base::ListValue* list) {
1508 std::string onc_blob;
1509 std::string passcode;
1510 if (list->GetSize() != 2 ||
1511 !list->GetString(0, &onc_blob) ||
1512 !list->GetString(1, &passcode)) {
1513 NOTREACHED();
1516 std::string error;
1517 const chromeos::User* user = chromeos::UserManager::Get()->GetActiveUser();
1518 if (user) {
1519 onc::ONCSource onc_source = onc::ONC_SOURCE_USER_IMPORT;
1521 base::ListValue network_configs;
1522 base::DictionaryValue global_network_config;
1523 base::ListValue certificates;
1524 if (!chromeos::onc::ParseAndValidateOncForImport(onc_blob,
1525 onc_source,
1526 passcode,
1527 &network_configs,
1528 &global_network_config,
1529 &certificates)) {
1530 error = "Errors occurred during the ONC parsing. ";
1533 chromeos::onc::CertificateImporterImpl cert_importer;
1534 if (!cert_importer.ImportCertificates(certificates, onc_source, NULL))
1535 error += "Some certificates couldn't be imported. ";
1537 std::string network_error;
1538 chromeos::onc::ImportNetworksForUser(user, network_configs, &network_error);
1539 if (!network_error.empty())
1540 error += network_error;
1541 } else {
1542 error = "No active user.";
1545 LOG_IF(ERROR, !error.empty()) << error;
1546 SendJavascriptCommand("receivedONCFileParse", new base::StringValue(error));
1549 void NetInternalsMessageHandler::OnStoreDebugLogs(const base::ListValue* list) {
1550 DCHECK(list);
1552 SendJavascriptCommand("receivedStoreDebugLogs",
1553 new base::StringValue("Creating log file..."));
1554 const DownloadPrefs* const prefs =
1555 DownloadPrefs::FromBrowserContext(Profile::FromWebUI(web_ui()));
1556 StoreDebugLogs(prefs->DownloadPath(),
1557 base::Bind(&NetInternalsMessageHandler::OnStoreDebugLogsCompleted,
1558 AsWeakPtr()));
1561 void NetInternalsMessageHandler::OnStoreDebugLogsCompleted(
1562 const base::FilePath& log_path, bool succeeded) {
1563 std::string status;
1564 if (succeeded)
1565 status = "Created log file: " + log_path.BaseName().AsUTF8Unsafe();
1566 else
1567 status = "Failed to create log file";
1568 SendJavascriptCommand("receivedStoreDebugLogs",
1569 new base::StringValue(status));
1572 void NetInternalsMessageHandler::OnSetNetworkDebugMode(
1573 const base::ListValue* list) {
1574 std::string subsystem;
1575 if (list->GetSize() != 1 || !list->GetString(0, &subsystem))
1576 NOTREACHED();
1577 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->
1578 SetDebugMode(
1579 subsystem,
1580 base::Bind(
1581 &NetInternalsMessageHandler::OnSetNetworkDebugModeCompleted,
1582 AsWeakPtr(),
1583 subsystem));
1586 void NetInternalsMessageHandler::OnSetNetworkDebugModeCompleted(
1587 const std::string& subsystem,
1588 bool succeeded) {
1589 std::string status;
1590 if (succeeded)
1591 status = "Debug mode is changed to " + subsystem;
1592 else
1593 status = "Failed to change debug mode to " + subsystem;
1594 SendJavascriptCommand("receivedSetNetworkDebugMode",
1595 new base::StringValue(status));
1597 #endif // defined(OS_CHROMEOS)
1599 void NetInternalsMessageHandler::IOThreadImpl::OnGetHttpPipeliningStatus(
1600 const base::ListValue* list) {
1601 DCHECK(!list);
1602 base::DictionaryValue* status_dict = new base::DictionaryValue();
1604 base::Value* pipelined_connection_info = NULL;
1605 net::HttpNetworkSession* http_network_session =
1606 GetHttpNetworkSession(GetMainContext());
1607 if (http_network_session) {
1608 status_dict->Set("pipelining_enabled", base::Value::CreateBooleanValue(
1609 http_network_session->params().http_pipelining_enabled));
1611 pipelined_connection_info =
1612 http_network_session->http_stream_factory()->PipelineInfoToValue();
1614 status_dict->Set("pipelined_connection_info", pipelined_connection_info);
1616 const net::HttpServerProperties& http_server_properties =
1617 *GetMainContext()->http_server_properties();
1619 // TODO(simonjam): This call is slow.
1620 const net::PipelineCapabilityMap pipeline_capability_map =
1621 http_server_properties.GetPipelineCapabilityMap();
1623 base::ListValue* known_hosts_list = new base::ListValue();
1624 net::PipelineCapabilityMap::const_iterator it;
1625 for (it = pipeline_capability_map.begin();
1626 it != pipeline_capability_map.end(); ++it) {
1627 base::DictionaryValue* host_dict = new base::DictionaryValue();
1628 host_dict->SetString("host", it->first.ToString());
1629 std::string capability;
1630 switch (it->second) {
1631 case net::PIPELINE_CAPABLE:
1632 capability = "capable";
1633 break;
1635 case net::PIPELINE_PROBABLY_CAPABLE:
1636 capability = "probably capable";
1637 break;
1639 case net::PIPELINE_INCAPABLE:
1640 capability = "incapable";
1641 break;
1643 case net::PIPELINE_UNKNOWN:
1644 default:
1645 capability = "unknown";
1646 break;
1648 host_dict->SetString("capability", capability);
1649 known_hosts_list->Append(host_dict);
1651 status_dict->Set("pipelined_host_info", known_hosts_list);
1653 SendJavascriptCommand("receivedHttpPipeliningStatus", status_dict);
1656 void NetInternalsMessageHandler::IOThreadImpl::OnSetLogLevel(
1657 const base::ListValue* list) {
1658 int log_level;
1659 std::string log_level_string;
1660 if (!list->GetString(0, &log_level_string) ||
1661 !base::StringToInt(log_level_string, &log_level)) {
1662 NOTREACHED();
1663 return;
1666 DCHECK_GE(log_level, net::NetLog::LOG_ALL);
1667 DCHECK_LE(log_level, net::NetLog::LOG_BASIC);
1668 net_log()->SetObserverLogLevel(
1669 this, static_cast<net::NetLog::LogLevel>(log_level));
1672 // Note that unlike other methods of IOThreadImpl, this function
1673 // can be called from ANY THREAD.
1674 void NetInternalsMessageHandler::IOThreadImpl::OnAddEntry(
1675 const net::NetLog::Entry& entry) {
1676 BrowserThread::PostTask(
1677 BrowserThread::IO, FROM_HERE,
1678 base::Bind(&IOThreadImpl::AddEntryToQueue, this, entry.ToValue()));
1681 void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTestSuite() {
1682 SendJavascriptCommand("receivedStartConnectionTestSuite", NULL);
1685 void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTestExperiment(
1686 const ConnectionTester::Experiment& experiment) {
1687 SendJavascriptCommand(
1688 "receivedStartConnectionTestExperiment",
1689 ExperimentToValue(experiment));
1692 void
1693 NetInternalsMessageHandler::IOThreadImpl::OnCompletedConnectionTestExperiment(
1694 const ConnectionTester::Experiment& experiment,
1695 int result) {
1696 base::DictionaryValue* dict = new base::DictionaryValue();
1698 dict->Set("experiment", ExperimentToValue(experiment));
1699 dict->SetInteger("result", result);
1701 SendJavascriptCommand(
1702 "receivedCompletedConnectionTestExperiment",
1703 dict);
1706 void
1707 NetInternalsMessageHandler::IOThreadImpl::OnCompletedConnectionTestSuite() {
1708 SendJavascriptCommand(
1709 "receivedCompletedConnectionTestSuite",
1710 NULL);
1713 // Note that this can be called from ANY THREAD.
1714 void NetInternalsMessageHandler::IOThreadImpl::SendJavascriptCommand(
1715 const std::string& command,
1716 base::Value* arg) {
1717 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
1718 if (handler_.get() && !was_webui_deleted_) {
1719 // We check |handler_| in case it was deleted on the UI thread earlier
1720 // while we were running on the IO thread.
1721 handler_->SendJavascriptCommand(command, arg);
1722 } else {
1723 delete arg;
1725 return;
1728 if (!BrowserThread::PostTask(
1729 BrowserThread::UI, FROM_HERE,
1730 base::Bind(&IOThreadImpl::SendJavascriptCommand, this, command, arg))) {
1731 // Failed posting the task, avoid leaking.
1732 delete arg;
1736 void NetInternalsMessageHandler::IOThreadImpl::AddEntryToQueue(
1737 base::Value* entry) {
1738 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1739 if (!pending_entries_.get()) {
1740 pending_entries_.reset(new base::ListValue());
1741 BrowserThread::PostDelayedTask(
1742 BrowserThread::IO, FROM_HERE,
1743 base::Bind(&IOThreadImpl::PostPendingEntries, this),
1744 base::TimeDelta::FromMilliseconds(kNetLogEventDelayMilliseconds));
1746 pending_entries_->Append(entry);
1749 void NetInternalsMessageHandler::IOThreadImpl::PostPendingEntries() {
1750 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1751 if (pending_entries_.get())
1752 SendJavascriptCommand("receivedLogEntries", pending_entries_.release());
1755 void NetInternalsMessageHandler::IOThreadImpl::PrePopulateEventList() {
1756 // Use a set to prevent duplicates.
1757 std::set<net::URLRequestContext*> contexts;
1758 for (ContextGetterList::const_iterator getter = context_getters_.begin();
1759 getter != context_getters_.end(); ++getter) {
1760 contexts.insert((*getter)->GetURLRequestContext());
1762 contexts.insert(io_thread_->globals()->proxy_script_fetcher_context.get());
1763 contexts.insert(io_thread_->globals()->system_request_context.get());
1765 // Put together the list of all requests.
1766 std::vector<const net::URLRequest*> requests;
1767 for (std::set<net::URLRequestContext*>::const_iterator context =
1768 contexts.begin();
1769 context != contexts.end(); ++context) {
1770 std::set<const net::URLRequest*>* context_requests =
1771 (*context)->url_requests();
1772 for (std::set<const net::URLRequest*>::const_iterator request_it =
1773 context_requests->begin();
1774 request_it != context_requests->end(); ++request_it) {
1775 DCHECK_EQ(io_thread_->net_log(), (*request_it)->net_log().net_log());
1776 requests.push_back(*request_it);
1780 // Sort by creation time.
1781 std::sort(requests.begin(), requests.end(), RequestCreatedBefore);
1783 // Create fake events.
1784 for (std::vector<const net::URLRequest*>::const_iterator request_it =
1785 requests.begin();
1786 request_it != requests.end(); ++request_it) {
1787 const net::URLRequest* request = *request_it;
1788 net::NetLog::ParametersCallback callback =
1789 base::Bind(&GetRequestStateAsValue, base::Unretained(request));
1791 // Create and add the entry directly, to avoid sending it to any other
1792 // NetLog observers.
1793 net::NetLog::Entry entry(net::NetLog::TYPE_REQUEST_ALIVE,
1794 request->net_log().source(),
1795 net::NetLog::PHASE_BEGIN,
1796 request->creation_time(),
1797 &callback,
1798 request->net_log().GetLogLevel());
1800 // Have to add |entry| to the queue synchronously, as there may already
1801 // be posted tasks queued up to add other events for |request|, which we
1802 // want |entry| to precede.
1803 AddEntryToQueue(entry.ToValue());
1807 } // namespace
1810 ////////////////////////////////////////////////////////////////////////////////
1812 // NetInternalsUI
1814 ////////////////////////////////////////////////////////////////////////////////
1816 // static
1817 base::Value* NetInternalsUI::GetConstants() {
1818 base::DictionaryValue* constants_dict = net::NetLogLogger::GetConstants();
1819 DCHECK(constants_dict);
1821 // Add a dictionary with the version of the client and its command line
1822 // arguments.
1824 base::DictionaryValue* dict = new base::DictionaryValue();
1826 chrome::VersionInfo version_info;
1828 if (!version_info.is_valid()) {
1829 DLOG(ERROR) << "Unable to create chrome::VersionInfo";
1830 } else {
1831 // We have everything we need to send the right values.
1832 dict->SetString("name", version_info.Name());
1833 dict->SetString("version", version_info.Version());
1834 dict->SetString("cl", version_info.LastChange());
1835 dict->SetString("version_mod",
1836 chrome::VersionInfo::GetVersionStringModifier());
1837 dict->SetString("official",
1838 version_info.IsOfficialBuild() ? "official" :
1839 "unofficial");
1840 dict->SetString("os_type", version_info.OSType());
1841 dict->SetString("command_line",
1842 CommandLine::ForCurrentProcess()->GetCommandLineString());
1845 constants_dict->Set("clientInfo", dict);
1848 return constants_dict;
1851 NetInternalsUI::NetInternalsUI(content::WebUI* web_ui)
1852 : WebUIController(web_ui) {
1853 web_ui->AddMessageHandler(new NetInternalsMessageHandler());
1855 // Set up the chrome://net-internals/ source.
1856 Profile* profile = Profile::FromWebUI(web_ui);
1857 content::WebUIDataSource::Add(profile, CreateNetInternalsHTMLSource());