Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / webui / net_internals / net_internals_ui.cc
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.
4
5 #include "chrome/browser/ui/webui/net_internals/net_internals_ui.h"
6
7 #include <algorithm>
8 #include <list>
9 #include <string>
10 #include <utility>
11 #include <vector>
12
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"
81
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"
92 #endif
93 #if defined(OS_WIN)
94 #include "chrome/browser/net/service_providers_win.h"
95 #endif
96
97 using base::StringValue;
98 using content::BrowserThread;
99 using content::WebContents;
100 using content::WebUIMessageHandler;
101
102 namespace {
103
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;
108
109 // Returns the HostCache for |context|'s primary HostResolver, or NULL if
110 // there is none.
111 net::HostCache* GetHostResolverCache(net::URLRequestContext* context) {
112   return context->host_resolver()->GetHostCache();
113 }
114
115 std::string HashesToBase64String(const net::HashValueVector& hashes) {
116   std::string str;
117   for (size_t i = 0; i != hashes.size(); ++i) {
118     if (i != 0)
119       str += ",";
120     str += hashes[i].ToString();
121   }
122   return str;
123 }
124
125 bool Base64StringToHashes(const std::string& hashes_str,
126                           net::HashValueVector* hashes) {
127   hashes->clear();
128   std::vector<std::string> vector_hash_str;
129   base::SplitString(hashes_str, ',', &vector_hash_str);
130
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);
134     net::HashValue hash;
135     // Skip past unrecognized hash algos
136     // But return false on malformatted input
137     if (hash_str.empty())
138       return false;
139     if (hash_str.compare(0, 5, "sha1/") != 0 &&
140         hash_str.compare(0, 7, "sha256/") != 0) {
141       continue;
142     }
143     if (!hash.FromString(hash_str))
144       return false;
145     hashes->push_back(hash);
146   }
147   return true;
148 }
149
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();
155 }
156
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();
161 }
162
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())
166     return NULL;
167
168   net::HttpCache* http_cache = context->http_transaction_factory()->GetCache();
169   if (!http_cache)
170     return NULL;
171
172   return http_cache->GetCurrentBackend();
173 }
174
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())
180     return NULL;
181
182   return context->http_transaction_factory()->GetSession();
183 }
184
185 base::Value* ExperimentToValue(const ConnectionTester::Experiment& experiment) {
186   base::DictionaryValue* dict = new base::DictionaryValue();
187
188   if (experiment.url.is_valid())
189     dict->SetString("url", experiment.url.spec());
190
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));
197   return dict;
198 }
199
200 content::WebUIDataSource* CreateNetInternalsHTMLSource() {
201   content::WebUIDataSource* source =
202       content::WebUIDataSource::Create(chrome::kChromeUINetInternalsHost);
203
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");
208   return source;
209 }
210
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(base::File file,
223                               const base::FilePath& file_path)>
224       DebugLogFileCallback;
225
226   DebugLogFileHelper() {}
227
228   ~DebugLogFileHelper() {}
229
230   void DoWork(const base::FilePath& fileshelf) {
231     const base::FilePath::CharType kLogFileName[] =
232         FILE_PATH_LITERAL("debug-log.tgz");
233
234     file_path_ = fileshelf.Append(kLogFileName);
235     file_path_ = logging::GenerateTimestampedName(file_path_,
236                                                   base::Time::Now());
237
238     int flags =  base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE;
239     file_.Initialize(file_path_, flags);
240   }
241
242   void Reply(const DebugLogFileCallback& callback) {
243     DCHECK(!callback.is_null());
244     callback.Run(file_.Pass(), file_path_);
245   }
246
247  private:
248   base::File file_;
249   base::FilePath file_path_;
250
251   DISALLOW_COPY_AND_ASSIGN(DebugLogFileHelper);
252 };
253
254 // Following functions are used for getting debug logs. Logs are
255 // fetched from /var/log/* and put on the fileshelf.
256
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;
262
263 // Closes file handle, so, should be called on the WorkerPool thread.
264 void CloseDebugLogFile(base::File file) {
265   file.Close();
266 }
267
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) {
272   file.Close();
273   base::DeleteFile(file_path, false);
274 }
275
276 // Called upon completion of |WriteDebugLogToFile|. Closes file
277 // descriptor, deletes log file in the case of failure and calls
278 // |callback|.
279 void WriteDebugLogToFileCompleted(const StoreDebugLogsCallback& callback,
280                                   base::File file,
281                                   const base::FilePath& file_path,
282                                   bool succeeded) {
283   DCHECK_CURRENTLY_ON(BrowserThread::UI);
284   if (!succeeded) {
285     bool posted = base::WorkerPool::PostTaskAndReply(FROM_HERE,
286         base::Bind(&CloseAndDeleteDebugLogFile, Passed(&file), file_path),
287         base::Bind(callback, file_path, false), false);
288     DCHECK(posted);
289     return;
290   }
291   bool posted = base::WorkerPool::PostTaskAndReply(FROM_HERE,
292       base::Bind(&CloseDebugLogFile, Passed(&file)),
293       base::Bind(callback, file_path, true), false);
294   DCHECK(posted);
295 }
296
297 // Stores into |file_path| debug logs in the .tgz format. Calls
298 // |callback| upon completion.
299 void WriteDebugLogToFile(const StoreDebugLogsCallback& callback,
300                          base::File file,
301                          const base::FilePath& file_path) {
302   DCHECK_CURRENTLY_ON(BrowserThread::UI);
303   if (!file.IsValid()) {
304     LOG(ERROR) <<
305         "Can't create debug log file: " << file_path.AsUTF8Unsafe() << ", " <<
306         "error: " << file.error_details();
307     return;
308   }
309   chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->GetDebugLogs(
310       file.GetPlatformFile(),
311       base::Bind(&WriteDebugLogToFileCompleted,
312                  callback, Passed(&file), file_path));
313 }
314
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);
329   DCHECK(posted);
330 }
331 #endif  // defined(OS_CHROMEOS)
332
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.
336 //
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.
340 //
341 // TODO(eroman): Can we start on the IO thread to begin with?
342 class NetInternalsMessageHandler
343     : public WebUIMessageHandler,
344       public base::SupportsWeakPtr<NetInternalsMessageHandler> {
345  public:
346   NetInternalsMessageHandler();
347   virtual ~NetInternalsMessageHandler();
348
349   // WebUIMessageHandler implementation.
350   virtual void RegisterMessages() OVERRIDE;
351
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);
356
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,
369                                  bool succeeded);
370   void OnSetNetworkDebugMode(const base::ListValue* list);
371   void OnSetNetworkDebugModeCompleted(const std::string& subsystem,
372                                       bool succeeded);
373
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);
380 #endif
381
382  private:
383   class IOThreadImpl;
384
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 {
394    public:
395     SystemLogsGetter(NetInternalsMessageHandler* handler,
396                      chromeos::system::SyslogsProvider* syslogs_provider);
397     ~SystemLogsGetter();
398
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
403     // back.
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);
416
417    private:
418     // Struct we save postponed log request in.
419     struct SystemLogRequest {
420       std::string log_key;
421       std::string cell_id;
422     };
423
424     // Processes request.
425     void SendLogs(const SystemLogRequest& request);
426
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_;
432     bool logs_received_;
433     bool logs_requested_;
434     base::CancelableTaskTracker tracker_;
435     // Libcros request task ID.
436     base::CancelableTaskTracker::TaskId syslogs_task_id_;
437   };
438 #endif  // defined(OS_CHROMEOS)
439
440   // This is the "real" message handler, which lives on the IO thread.
441   scoped_refptr<IOThreadImpl> proxy_;
442
443   base::WeakPtr<prerender::PrerenderManager> prerender_manager_;
444
445 #if defined(OS_CHROMEOS)
446   // Class that handles getting and filtering system logs.
447   scoped_ptr<SystemLogsGetter> syslogs_getter_;
448 #endif
449
450   DISALLOW_COPY_AND_ASSIGN(NetInternalsMessageHandler);
451 };
452
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 {
464  public:
465   // Type for methods that can be used as MessageHandler callbacks.
466   typedef void (IOThreadImpl::*MessageHandler)(const base::ListValue*);
467
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).
473   IOThreadImpl(
474       const base::WeakPtr<NetInternalsMessageHandler>& handler,
475       IOThread* io_thread,
476       net::URLRequestContextGetter* main_context_getter);
477
478   // Called on UI thread just after creation, to add a ContextGetter to
479   // |context_getters_|.
480   void AddRequestContextGetter(net::URLRequestContextGetter* context_getter);
481
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);
486
487   // Called once the WebUI has been deleted (i.e. renderer went away), on the
488   // IO thread.
489   void Detach();
490
491   // Called when the WebUI is deleted.  Prevents calling Javascript functions
492   // afterwards.  Called on UI thread.
493   void OnWebUIDeleted();
494
495   //--------------------------------
496   // Javascript message handlers:
497   //--------------------------------
498
499   void OnRendererReady(const base::ListValue* list);
500
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);
521 #if defined(OS_WIN)
522   void OnGetServiceProviders(const base::ListValue* list);
523 #endif
524   void OnGetHttpPipeliningStatus(const base::ListValue* list);
525   void OnSetLogLevel(const base::ListValue* list);
526
527   // ChromeNetLog::ThreadSafeObserver implementation:
528   virtual void OnAddEntry(const net::NetLog::Entry& entry) OVERRIDE;
529
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;
538
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
542   // thread.
543   void SendJavascriptCommand(const std::string& command, base::Value* arg);
544
545  private:
546   friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>;
547   friend class base::DeleteHelper<IOThreadImpl>;
548
549   typedef std::list<scoped_refptr<net::URLRequestContextGetter> >
550       ContextGetterList;
551
552   virtual ~IOThreadImpl();
553
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);
558
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();
564
565   // Adds entries with the states of ongoing URL requests.
566   void PrePopulateEventList();
567
568   net::URLRequestContext* GetMainContext() {
569     return main_context_getter_->GetURLRequestContext();
570   }
571
572   // Pointer to the UI-thread message handler. Only access this from
573   // the UI thread.
574   base::WeakPtr<NetInternalsMessageHandler> handler_;
575
576   // The global IOThread, which contains the global NetLog to observer.
577   IOThread* io_thread_;
578
579   // The main URLRequestContextGetter for the tab's profile.
580   scoped_refptr<net::URLRequestContextGetter> main_context_getter_;
581
582   // Helper that runs the suite of connection tests.
583   scoped_ptr<ConnectionTester> connection_tester_;
584
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.
589   //
590   // This is only read and written to on the UI thread.
591   bool was_webui_deleted_;
592
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_;
597
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_;
602
603   DISALLOW_COPY_AND_ASSIGN(IOThreadImpl);
604 };
605
606 ////////////////////////////////////////////////////////////////////////////////
607 //
608 // NetInternalsMessageHandler
609 //
610 ////////////////////////////////////////////////////////////////////////////////
611
612 NetInternalsMessageHandler::NetInternalsMessageHandler() {}
613
614 NetInternalsMessageHandler::~NetInternalsMessageHandler() {
615   if (proxy_.get()) {
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()));
620   }
621 }
622
623 void NetInternalsMessageHandler::RegisterMessages() {
624   DCHECK_CURRENTLY_ON(BrowserThread::UI);
625
626   Profile* profile = Profile::FromWebUI(web_ui());
627
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()));
635 #endif
636
637   prerender::PrerenderManager* prerender_manager =
638       prerender::PrerenderManagerFactory::GetForProfile(profile);
639   if (prerender_manager) {
640     prerender_manager_ = prerender_manager->AsWeakPtr();
641   } else {
642     prerender_manager_ = base::WeakPtr<prerender::PrerenderManager>();
643   }
644
645   web_ui()->RegisterMessageCallback(
646       "notifyReady",
647       base::Bind(&NetInternalsMessageHandler::OnRendererReady,
648                  base::Unretained(this)));
649   web_ui()->RegisterMessageCallback(
650       "getProxySettings",
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(
658       "getBadProxies",
659       base::Bind(&IOThreadImpl::CallbackHelper,
660                  &IOThreadImpl::OnGetBadProxies, proxy_));
661   web_ui()->RegisterMessageCallback(
662       "clearBadProxies",
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(
674       "enableIPv6",
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(
682       "hstsQuery",
683       base::Bind(&IOThreadImpl::CallbackHelper,
684                  &IOThreadImpl::OnHSTSQuery, proxy_));
685   web_ui()->RegisterMessageCallback(
686       "hstsAdd",
687       base::Bind(&IOThreadImpl::CallbackHelper,
688                  &IOThreadImpl::OnHSTSAdd, proxy_));
689   web_ui()->RegisterMessageCallback(
690       "hstsDelete",
691       base::Bind(&IOThreadImpl::CallbackHelper,
692                  &IOThreadImpl::OnHSTSDelete, proxy_));
693   web_ui()->RegisterMessageCallback(
694       "getHttpCacheInfo",
695       base::Bind(&IOThreadImpl::CallbackHelper,
696                  &IOThreadImpl::OnGetHttpCacheInfo, proxy_));
697   web_ui()->RegisterMessageCallback(
698       "getSocketPoolInfo",
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(
706       "closeIdleSockets",
707       base::Bind(&IOThreadImpl::CallbackHelper,
708                  &IOThreadImpl::OnCloseIdleSockets, proxy_));
709   web_ui()->RegisterMessageCallback(
710       "flushSocketPools",
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(
718       "getSpdyStatus",
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(
726       "getQuicInfo",
727       base::Bind(&IOThreadImpl::CallbackHelper,
728                  &IOThreadImpl::OnGetQuicInfo, proxy_));
729 #if defined(OS_WIN)
730   web_ui()->RegisterMessageCallback(
731       "getServiceProviders",
732       base::Bind(&IOThreadImpl::CallbackHelper,
733                  &IOThreadImpl::OnGetServiceProviders, proxy_));
734 #endif
735
736   web_ui()->RegisterMessageCallback(
737       "getHttpPipeliningStatus",
738       base::Bind(&IOThreadImpl::CallbackHelper,
739                  &IOThreadImpl::OnGetHttpPipeliningStatus, proxy_));
740   web_ui()->RegisterMessageCallback(
741       "setLogLevel",
742       base::Bind(&IOThreadImpl::CallbackHelper,
743                  &IOThreadImpl::OnSetLogLevel, proxy_));
744   web_ui()->RegisterMessageCallback(
745       "clearBrowserCache",
746       base::Bind(&NetInternalsMessageHandler::OnClearBrowserCache,
747                  base::Unretained(this)));
748   web_ui()->RegisterMessageCallback(
749       "getPrerenderInfo",
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(
757       "getExtensionInfo",
758       base::Bind(&NetInternalsMessageHandler::OnGetExtensionInfo,
759                  base::Unretained(this)));
760 #if defined(OS_CHROMEOS)
761   web_ui()->RegisterMessageCallback(
762       "refreshSystemLogs",
763       base::Bind(&NetInternalsMessageHandler::OnRefreshSystemLogs,
764                  base::Unretained(this)));
765   web_ui()->RegisterMessageCallback(
766       "getSystemLog",
767       base::Bind(&NetInternalsMessageHandler::OnGetSystemLog,
768                  base::Unretained(this)));
769   web_ui()->RegisterMessageCallback(
770       "importONCFile",
771       base::Bind(&NetInternalsMessageHandler::OnImportONCFile,
772                  base::Unretained(this)));
773   web_ui()->RegisterMessageCallback(
774       "storeDebugLogs",
775       base::Bind(&NetInternalsMessageHandler::OnStoreDebugLogs,
776                  base::Unretained(this)));
777   web_ui()->RegisterMessageCallback(
778       "setNetworkDebugMode",
779       base::Bind(&NetInternalsMessageHandler::OnSetNetworkDebugMode,
780                  base::Unretained(this)));
781 #endif
782 }
783
784 void NetInternalsMessageHandler::SendJavascriptCommand(
785     const std::string& command,
786     base::Value* arg) {
787   scoped_ptr<base::Value> command_value(new base::StringValue(command));
788   scoped_ptr<base::Value> value(arg);
789   DCHECK_CURRENTLY_ON(BrowserThread::UI);
790   if (value.get()) {
791     web_ui()->CallJavascriptFunction("g_browser.receive",
792                                      *command_value.get(),
793                                      *value.get());
794   } else {
795     web_ui()->CallJavascriptFunction("g_browser.receive",
796                                      *command_value.get());
797   }
798 }
799
800 void NetInternalsMessageHandler::OnRendererReady(const base::ListValue* list) {
801   IOThreadImpl::CallbackHelper(&IOThreadImpl::OnRendererReady, proxy_, list);
802 }
803
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.
811 }
812
813 void NetInternalsMessageHandler::OnGetPrerenderInfo(
814     const base::ListValue* list) {
815   DCHECK_CURRENTLY_ON(BrowserThread::UI);
816
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);
823   } else {
824     value = prerender_manager->GetAsValue();
825   }
826   SendJavascriptCommand("receivedPrerenderInfo", value);
827 }
828
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);
835 }
836
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);
856       }
857     }
858   }
859   SendJavascriptCommand("receivedExtensionInfo", extension_list);
860 }
861
862 #if defined(OS_CHROMEOS)
863 ////////////////////////////////////////////////////////////////////////////////
864 //
865 // NetInternalsMessageHandler::SystemLogsGetter
866 //
867 ////////////////////////////////////////////////////////////////////////////////
868
869 NetInternalsMessageHandler::SystemLogsGetter::SystemLogsGetter(
870     NetInternalsMessageHandler* handler,
871     chromeos::system::SyslogsProvider* syslogs_provider)
872     : handler_(handler),
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";
878 }
879
880 NetInternalsMessageHandler::SystemLogsGetter::~SystemLogsGetter() {
881   DeleteSystemLogs();
882 }
883
884 void NetInternalsMessageHandler::SystemLogsGetter::DeleteSystemLogs() {
885   if (syslogs_provider_ && logs_requested_ && !logs_received_) {
886     tracker_.TryCancel(syslogs_task_id_);
887   }
888   logs_requested_ = false;
889   logs_received_ = false;
890   logs_.reset();
891 }
892
893 void NetInternalsMessageHandler::SystemLogsGetter::RequestSystemLog(
894     const base::ListValue* args) {
895   if (!logs_requested_) {
896     DCHECK(!logs_received_);
897     LoadSystemLogs();
898   }
899   SystemLogRequest log_request;
900   args->GetString(0, &log_request.log_key);
901   args->GetString(1, &log_request.cell_id);
902
903   if (logs_received_) {
904     SendLogs(log_request);
905   } else {
906     requests_.push_back(log_request);
907   }
908 }
909
910 void NetInternalsMessageHandler::SystemLogsGetter::LoadSystemLogs() {
911   if (logs_requested_ || !syslogs_provider_)
912     return;
913   logs_requested_ = true;
914   syslogs_task_id_ = syslogs_provider_->RequestSyslogs(
915       false,  // compress logs.
916       chromeos::system::SyslogsProvider::SYSLOGS_NETWORK,
917       base::Bind(
918           &NetInternalsMessageHandler::SystemLogsGetter::OnSystemLogsLoaded,
919           base::Unretained(this)),
920       &tracker_);
921 }
922
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();
931        ++request_it) {
932     SendLogs(*request_it);
933   }
934   requests_.clear();
935 }
936
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);
945     } else {
946       result->SetString("log", "<no relevant lines found>");
947     }
948   } else {
949     result->SetString("log", "<invalid log name>");
950   }
951   result->SetString("cellId", request.cell_id);
952
953   handler_->SendJavascriptCommand("getSystemLogCallback", result);
954 }
955 #endif  // defined(OS_CHROMEOS)
956
957 ////////////////////////////////////////////////////////////////////////////////
958 //
959 // NetInternalsMessageHandler::IOThreadImpl
960 //
961 ////////////////////////////////////////////////////////////////////////////////
962
963 NetInternalsMessageHandler::IOThreadImpl::IOThreadImpl(
964     const base::WeakPtr<NetInternalsMessageHandler>& handler,
965     IOThread* io_thread,
966     net::URLRequestContextGetter* main_context_getter)
967     : handler_(handler),
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);
973 }
974
975 NetInternalsMessageHandler::IOThreadImpl::~IOThreadImpl() {
976   DCHECK_CURRENTLY_ON(BrowserThread::UI);
977 }
978
979 void NetInternalsMessageHandler::IOThreadImpl::AddRequestContextGetter(
980     net::URLRequestContextGetter* context_getter) {
981   DCHECK_CURRENTLY_ON(BrowserThread::UI);
982   context_getters_.push_back(context_getter);
983 }
984
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);
990
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;
996
997   BrowserThread::PostTask(
998       BrowserThread::IO, FROM_HERE,
999       base::Bind(method, io_thread, base::Owned(list_copy)));
1000 }
1001
1002 void NetInternalsMessageHandler::IOThreadImpl::Detach() {
1003   DCHECK_CURRENTLY_ON(BrowserThread::IO);
1004   // Unregister with network stack to observe events.
1005   if (net_log())
1006     net_log()->RemoveThreadSafeObserver(this);
1007
1008   // Cancel any in-progress connection tests.
1009   connection_tester_.reset();
1010 }
1011
1012 void NetInternalsMessageHandler::IOThreadImpl::OnWebUIDeleted() {
1013   DCHECK_CURRENTLY_ON(BrowserThread::UI);
1014   was_webui_deleted_ = true;
1015 }
1016
1017 void NetInternalsMessageHandler::IOThreadImpl::OnRendererReady(
1018     const base::ListValue* list) {
1019   DCHECK_CURRENTLY_ON(BrowserThread::IO);
1020
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
1023   // URLRequests.
1024   PostPendingEntries();
1025
1026   SendJavascriptCommand("receivedConstants", NetInternalsUI::GetConstants());
1027
1028   // Add entries for ongoing URL requests.
1029   PrePopulateEventList();
1030
1031   if (!net_log()) {
1032     // Register with network stack to observe events.
1033     io_thread_->net_log()->AddThreadSafeObserver(this,
1034         net::NetLog::LOG_ALL_BUT_BYTES);
1035   }
1036 }
1037
1038 void NetInternalsMessageHandler::IOThreadImpl::OnGetProxySettings(
1039     const base::ListValue* list) {
1040   DCHECK(!list);
1041   net::ProxyService* proxy_service = GetMainContext()->proxy_service();
1042
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());
1048
1049   SendJavascriptCommand("receivedProxySettings", dict);
1050 }
1051
1052 void NetInternalsMessageHandler::IOThreadImpl::OnReloadProxySettings(
1053     const base::ListValue* list) {
1054   DCHECK(!list);
1055   GetMainContext()->proxy_service()->ForceReloadProxyConfig();
1056
1057   // Cause the renderer to be notified of the new values.
1058   OnGetProxySettings(NULL);
1059 }
1060
1061 void NetInternalsMessageHandler::IOThreadImpl::OnGetBadProxies(
1062     const base::ListValue* list) {
1063   DCHECK(!list);
1064
1065   const net::ProxyRetryInfoMap& bad_proxies_map =
1066       GetMainContext()->proxy_service()->proxy_retry_info();
1067
1068   base::ListValue* dict_list = new base::ListValue();
1069
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;
1074
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));
1079
1080     dict_list->Append(dict);
1081   }
1082
1083   SendJavascriptCommand("receivedBadProxies", dict_list);
1084 }
1085
1086 void NetInternalsMessageHandler::IOThreadImpl::OnClearBadProxies(
1087     const base::ListValue* list) {
1088   DCHECK(!list);
1089   GetMainContext()->proxy_service()->ClearBadProxiesCache();
1090
1091   // Cause the renderer to be notified of the new values.
1092   OnGetBadProxies(NULL);
1093 }
1094
1095 void NetInternalsMessageHandler::IOThreadImpl::OnGetHostResolverInfo(
1096     const base::ListValue* list) {
1097   DCHECK(!list);
1098   net::URLRequestContext* context = GetMainContext();
1099   net::HostCache* cache = GetHostResolverCache(context);
1100
1101   if (!cache) {
1102     SendJavascriptCommand("receivedHostResolverInfo", NULL);
1103     return;
1104   }
1105
1106   base::DictionaryValue* dict = new base::DictionaryValue();
1107
1108   base::Value* dns_config = context->host_resolver()->GetDnsConfigAsValue();
1109   if (dns_config)
1110     dict->Set("dns_config", dns_config);
1111
1112   dict->SetInteger(
1113       "default_address_family",
1114       static_cast<int>(context->host_resolver()->GetDefaultAddressFamily()));
1115
1116   base::DictionaryValue* cache_info_dict = new base::DictionaryValue();
1117
1118   cache_info_dict->SetInteger(
1119       "capacity",
1120       static_cast<int>(cache->max_entries()));
1121
1122   base::ListValue* entry_list = new base::ListValue();
1123
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();
1128
1129     base::DictionaryValue* entry_dict = new base::DictionaryValue();
1130
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()));
1136
1137     if (entry.error != net::OK) {
1138       entry_dict->SetInteger("error", entry.error);
1139     } else {
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());
1144       }
1145       entry_dict->Set("addresses", address_list);
1146     }
1147
1148     entry_list->Append(entry_dict);
1149   }
1150
1151   cache_info_dict->Set("entries", entry_list);
1152   dict->Set("cache", cache_info_dict);
1153
1154   SendJavascriptCommand("receivedHostResolverInfo", dict);
1155 }
1156
1157 void NetInternalsMessageHandler::IOThreadImpl::OnClearHostResolverCache(
1158     const base::ListValue* list) {
1159   DCHECK(!list);
1160   net::HostCache* cache = GetHostResolverCache(GetMainContext());
1161
1162   if (cache)
1163     cache->clear();
1164
1165   // Cause the renderer to be notified of the new values.
1166   OnGetHostResolverInfo(NULL);
1167 }
1168
1169 void NetInternalsMessageHandler::IOThreadImpl::OnEnableIPv6(
1170     const base::ListValue* list) {
1171   DCHECK(!list);
1172   net::HostResolver* host_resolver = GetMainContext()->host_resolver();
1173
1174   host_resolver->SetDefaultAddressFamily(net::ADDRESS_FAMILY_UNSPECIFIED);
1175
1176   // Cause the renderer to be notified of the new value.
1177   OnGetHostResolverInfo(NULL);
1178 }
1179
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));
1185
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()));
1189
1190   connection_tester_.reset(new ConnectionTester(
1191       this,
1192       io_thread_->globals()->proxy_script_fetcher_context.get(),
1193       net_log()));
1194   connection_tester_->RunAllTests(url);
1195 }
1196
1197 void NetInternalsMessageHandler::IOThreadImpl::OnHSTSQuery(
1198     const base::ListValue* list) {
1199   // |list| should be: [<domain to query>].
1200   std::string domain;
1201   CHECK(list->GetString(0, &domain));
1202   base::DictionaryValue* result = new base::DictionaryValue();
1203
1204   if (!base::IsStringASCII(domain)) {
1205     result->SetString("error", "non-ASCII domain name");
1206   } else {
1207     net::TransportSecurityState* transport_security_state =
1208         GetMainContext()->transport_security_state();
1209     if (!transport_security_state) {
1210       result->SetString("error", "no TransportSecurityState active");
1211     } else {
1212       net::TransportSecurityState::DomainState static_state;
1213       const bool found_static = transport_security_state->GetStaticDomainState(
1214           domain, true, &static_state);
1215       if (found_static) {
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));
1236       }
1237
1238       net::TransportSecurityState::DomainState dynamic_state;
1239       const bool found_dynamic =
1240           transport_security_state->GetDynamicDomainState(domain,
1241                                                           &dynamic_state);
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));
1259       }
1260
1261       result->SetBoolean("result", found_static || found_dynamic);
1262       if (found_static) {
1263         result->SetString("domain", static_state.domain);
1264       } else if (found_dynamic) {
1265         result->SetString("domain", dynamic_state.domain);
1266       } else {
1267         result->SetString("domain", domain);
1268       }
1269     }
1270   }
1271
1272   SendJavascriptCommand("receivedHSTSResult", result);
1273 }
1274
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>].
1279   std::string domain;
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
1283     // name.
1284     return;
1285   }
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));
1292
1293   net::TransportSecurityState* transport_security_state =
1294       GetMainContext()->transport_security_state();
1295   if (!transport_security_state)
1296     return;
1297
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))
1302       return;
1303   }
1304
1305   transport_security_state->AddHSTS(domain, expiry, sts_include_subdomains);
1306   transport_security_state->AddHPKP(domain, expiry, pkp_include_subdomains,
1307                                     hashes);
1308 }
1309
1310 void NetInternalsMessageHandler::IOThreadImpl::OnHSTSDelete(
1311     const base::ListValue* list) {
1312   // |list| should be: [<domain to query>].
1313   std::string domain;
1314   CHECK(list->GetString(0, &domain));
1315   if (!base::IsStringASCII(domain)) {
1316     // There cannot be a unicode entry in the HSTS set.
1317     return;
1318   }
1319   net::TransportSecurityState* transport_security_state =
1320       GetMainContext()->transport_security_state();
1321   if (!transport_security_state)
1322     return;
1323
1324   transport_security_state->DeleteDynamicDataForHost(domain);
1325 }
1326
1327 void NetInternalsMessageHandler::IOThreadImpl::OnGetHttpCacheInfo(
1328     const base::ListValue* list) {
1329   DCHECK(!list);
1330   base::DictionaryValue* info_dict = new base::DictionaryValue();
1331   base::DictionaryValue* stats_dict = new base::DictionaryValue();
1332
1333   disk_cache::Backend* disk_cache = GetDiskCacheBackend(GetMainContext());
1334
1335   if (disk_cache) {
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);
1342     }
1343   }
1344
1345   info_dict->Set("stats", stats_dict);
1346
1347   SendJavascriptCommand("receivedHttpCacheInfo", info_dict);
1348 }
1349
1350 void NetInternalsMessageHandler::IOThreadImpl::OnGetSocketPoolInfo(
1351     const base::ListValue* list) {
1352   DCHECK(!list);
1353   net::HttpNetworkSession* http_network_session =
1354       GetHttpNetworkSession(GetMainContext());
1355
1356   base::Value* socket_pool_info = NULL;
1357   if (http_network_session)
1358     socket_pool_info = http_network_session->SocketPoolInfoToValue();
1359
1360   SendJavascriptCommand("receivedSocketPoolInfo", socket_pool_info);
1361 }
1362
1363 void NetInternalsMessageHandler::IOThreadImpl::OnGetSessionNetworkStats(
1364     const base::ListValue* list) {
1365   DCHECK(!list);
1366   net::HttpNetworkSession* http_network_session =
1367       GetHttpNetworkSession(main_context_getter_->GetURLRequestContext());
1368
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());
1374     if (net_delegate) {
1375       network_info = net_delegate->SessionNetworkStatsInfoToValue();
1376     }
1377   }
1378   SendJavascriptCommand("receivedSessionNetworkStats", network_info);
1379 }
1380
1381 void NetInternalsMessageHandler::IOThreadImpl::OnFlushSocketPools(
1382     const base::ListValue* list) {
1383   DCHECK(!list);
1384   net::HttpNetworkSession* http_network_session =
1385       GetHttpNetworkSession(GetMainContext());
1386
1387   if (http_network_session)
1388     http_network_session->CloseAllConnections();
1389 }
1390
1391 void NetInternalsMessageHandler::IOThreadImpl::OnCloseIdleSockets(
1392     const base::ListValue* list) {
1393   DCHECK(!list);
1394   net::HttpNetworkSession* http_network_session =
1395       GetHttpNetworkSession(GetMainContext());
1396
1397   if (http_network_session)
1398     http_network_session->CloseIdleConnections();
1399 }
1400
1401 void NetInternalsMessageHandler::IOThreadImpl::OnGetSpdySessionInfo(
1402     const base::ListValue* list) {
1403   DCHECK(!list);
1404   net::HttpNetworkSession* http_network_session =
1405       GetHttpNetworkSession(GetMainContext());
1406
1407   base::Value* spdy_info = http_network_session ?
1408       http_network_session->SpdySessionPoolInfoToValue() : NULL;
1409   SendJavascriptCommand("receivedSpdySessionInfo", spdy_info);
1410 }
1411
1412 void NetInternalsMessageHandler::IOThreadImpl::OnGetSpdyStatus(
1413     const base::ListValue* list) {
1414   DCHECK(!list);
1415   base::DictionaryValue* status_dict = new base::DictionaryValue();
1416
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()));
1429
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(), ',');
1434   }
1435   status_dict->SetString("next_protos", next_protos_string);
1436
1437   SendJavascriptCommand("receivedSpdyStatus", status_dict);
1438 }
1439
1440 void
1441 NetInternalsMessageHandler::IOThreadImpl::OnGetSpdyAlternateProtocolMappings(
1442     const base::ListValue* list) {
1443   DCHECK(!list);
1444   base::ListValue* dict_list = new base::ListValue();
1445
1446   const net::HttpServerProperties& http_server_properties =
1447       *GetMainContext()->http_server_properties();
1448
1449   const net::AlternateProtocolMap& map =
1450       http_server_properties.alternate_protocol_map();
1451
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);
1458   }
1459
1460   SendJavascriptCommand("receivedSpdyAlternateProtocolMappings", dict_list);
1461 }
1462
1463 void NetInternalsMessageHandler::IOThreadImpl::OnGetQuicInfo(
1464     const base::ListValue* list) {
1465   DCHECK(!list);
1466   net::HttpNetworkSession* http_network_session =
1467       GetHttpNetworkSession(GetMainContext());
1468
1469   base::Value* quic_info = http_network_session ?
1470       http_network_session->QuicInfoToValue() : NULL;
1471   SendJavascriptCommand("receivedQuicInfo", quic_info);
1472 }
1473
1474 #if defined(OS_WIN)
1475 void NetInternalsMessageHandler::IOThreadImpl::OnGetServiceProviders(
1476     const base::ListValue* list) {
1477   DCHECK(!list);
1478
1479   base::DictionaryValue* service_providers = new base::DictionaryValue();
1480
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);
1493
1494     layered_provider_list->Append(service_dict);
1495   }
1496   service_providers->Set("service_providers", layered_provider_list);
1497
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);
1507
1508     namespace_list->Append(namespace_dict);
1509   }
1510   service_providers->Set("namespace_providers", namespace_list);
1511
1512   SendJavascriptCommand("receivedServiceProviders", service_providers);
1513 }
1514 #endif
1515
1516 #if defined(OS_CHROMEOS)
1517 void NetInternalsMessageHandler::OnRefreshSystemLogs(
1518     const base::ListValue* list) {
1519   DCHECK(!list);
1520   DCHECK(syslogs_getter_.get());
1521   syslogs_getter_->DeleteSystemLogs();
1522   syslogs_getter_->LoadSystemLogs();
1523 }
1524
1525 void NetInternalsMessageHandler::OnGetSystemLog(
1526     const base::ListValue* list) {
1527   DCHECK(syslogs_getter_.get());
1528   syslogs_getter_->RequestSystemLog(list);
1529 }
1530
1531 void NetInternalsMessageHandler::ImportONCFileToNSSDB(
1532     const std::string& onc_blob,
1533     const std::string& passcode,
1534     net::NSSCertDatabase* nssdb) {
1535   std::string error;
1536   chromeos::User* user = chromeos::UserManager::Get()->GetUserByProfile(
1537       Profile::FromWebUI(web_ui()));
1538
1539   if (user) {
1540     onc::ONCSource onc_source = onc::ONC_SOURCE_USER_IMPORT;
1541
1542     base::ListValue network_configs;
1543     base::DictionaryValue global_network_config;
1544     base::ListValue certificates;
1545     if (!chromeos::onc::ParseAndValidateOncForImport(onc_blob,
1546                                                      onc_source,
1547                                                      passcode,
1548                                                      &network_configs,
1549                                                      &global_network_config,
1550                                                      &certificates)) {
1551       error = "Errors occurred during the ONC parsing. ";
1552     }
1553
1554     chromeos::onc::CertificateImporterImpl cert_importer(nssdb);
1555     if (!cert_importer.ImportCertificates(certificates, onc_source, NULL))
1556       error += "Some certificates couldn't be imported. ";
1557
1558     std::string network_error;
1559     chromeos::onc::ImportNetworksForUser(user, network_configs, &network_error);
1560     if (!network_error.empty())
1561       error += network_error;
1562   } else {
1563     error = "User not found.";
1564   }
1565
1566   LOG_IF(ERROR, !error.empty()) << error;
1567   SendJavascriptCommand("receivedONCFileParse", new base::StringValue(error));
1568 }
1569
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)) {
1577     NOTREACHED();
1578   }
1579
1580   GetNSSCertDatabaseForProfile(
1581       Profile::FromWebUI(web_ui()),
1582       base::Bind(&NetInternalsMessageHandler::ImportONCFileToNSSDB, AsWeakPtr(),
1583                  onc_blob, passcode));
1584 }
1585
1586 void NetInternalsMessageHandler::OnStoreDebugLogs(const base::ListValue* list) {
1587   DCHECK(list);
1588
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,
1595                  AsWeakPtr()));
1596 }
1597
1598 void NetInternalsMessageHandler::OnStoreDebugLogsCompleted(
1599     const base::FilePath& log_path, bool succeeded) {
1600   std::string status;
1601   if (succeeded)
1602     status = "Created log file: " + log_path.BaseName().AsUTF8Unsafe();
1603   else
1604     status = "Failed to create log file";
1605   SendJavascriptCommand("receivedStoreDebugLogs",
1606                         new base::StringValue(status));
1607 }
1608
1609 void NetInternalsMessageHandler::OnSetNetworkDebugMode(
1610     const base::ListValue* list) {
1611   std::string subsystem;
1612   if (list->GetSize() != 1 || !list->GetString(0, &subsystem))
1613     NOTREACHED();
1614   chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->
1615       SetDebugMode(
1616           subsystem,
1617           base::Bind(
1618               &NetInternalsMessageHandler::OnSetNetworkDebugModeCompleted,
1619               AsWeakPtr(),
1620               subsystem));
1621 }
1622
1623 void NetInternalsMessageHandler::OnSetNetworkDebugModeCompleted(
1624     const std::string& subsystem,
1625     bool succeeded) {
1626   std::string status;
1627   if (succeeded)
1628     status = "Debug mode is changed to " + subsystem;
1629   else
1630     status = "Failed to change debug mode to " + subsystem;
1631   SendJavascriptCommand("receivedSetNetworkDebugMode",
1632                         new base::StringValue(status));
1633 }
1634 #endif  // defined(OS_CHROMEOS)
1635
1636 void NetInternalsMessageHandler::IOThreadImpl::OnGetHttpPipeliningStatus(
1637     const base::ListValue* list) {
1638   DCHECK(!list);
1639   base::DictionaryValue* status_dict = new base::DictionaryValue();
1640
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));
1647
1648     pipelined_connection_info =
1649         http_network_session->http_stream_factory()->PipelineInfoToValue();
1650   }
1651   status_dict->Set("pipelined_connection_info", pipelined_connection_info);
1652
1653   const net::HttpServerProperties& http_server_properties =
1654       *GetMainContext()->http_server_properties();
1655
1656   // TODO(simonjam): This call is slow.
1657   const net::PipelineCapabilityMap pipeline_capability_map =
1658       http_server_properties.GetPipelineCapabilityMap();
1659
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";
1670         break;
1671
1672       case net::PIPELINE_PROBABLY_CAPABLE:
1673         capability = "probably capable";
1674         break;
1675
1676       case net::PIPELINE_INCAPABLE:
1677         capability = "incapable";
1678         break;
1679
1680       case net::PIPELINE_UNKNOWN:
1681       default:
1682         capability = "unknown";
1683         break;
1684     }
1685     host_dict->SetString("capability", capability);
1686     known_hosts_list->Append(host_dict);
1687   }
1688   status_dict->Set("pipelined_host_info", known_hosts_list);
1689
1690   SendJavascriptCommand("receivedHttpPipeliningStatus", status_dict);
1691 }
1692
1693 void NetInternalsMessageHandler::IOThreadImpl::OnSetLogLevel(
1694     const base::ListValue* list) {
1695   int log_level;
1696   std::string log_level_string;
1697   if (!list->GetString(0, &log_level_string) ||
1698       !base::StringToInt(log_level_string, &log_level)) {
1699     NOTREACHED();
1700     return;
1701   }
1702
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));
1707 }
1708
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()));
1716 }
1717
1718 void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTestSuite() {
1719   SendJavascriptCommand("receivedStartConnectionTestSuite", NULL);
1720 }
1721
1722 void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTestExperiment(
1723     const ConnectionTester::Experiment& experiment) {
1724   SendJavascriptCommand(
1725       "receivedStartConnectionTestExperiment",
1726       ExperimentToValue(experiment));
1727 }
1728
1729 void
1730 NetInternalsMessageHandler::IOThreadImpl::OnCompletedConnectionTestExperiment(
1731     const ConnectionTester::Experiment& experiment,
1732     int result) {
1733   base::DictionaryValue* dict = new base::DictionaryValue();
1734
1735   dict->Set("experiment", ExperimentToValue(experiment));
1736   dict->SetInteger("result", result);
1737
1738   SendJavascriptCommand(
1739       "receivedCompletedConnectionTestExperiment",
1740       dict);
1741 }
1742
1743 void
1744 NetInternalsMessageHandler::IOThreadImpl::OnCompletedConnectionTestSuite() {
1745   SendJavascriptCommand(
1746       "receivedCompletedConnectionTestSuite",
1747       NULL);
1748 }
1749
1750 // Note that this can be called from ANY THREAD.
1751 void NetInternalsMessageHandler::IOThreadImpl::SendJavascriptCommand(
1752     const std::string& command,
1753     base::Value* arg) {
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);
1759     } else {
1760       delete arg;
1761     }
1762     return;
1763   }
1764
1765   if (!BrowserThread::PostTask(
1766       BrowserThread::UI, FROM_HERE,
1767       base::Bind(&IOThreadImpl::SendJavascriptCommand, this, command, arg))) {
1768     // Failed posting the task, avoid leaking.
1769     delete arg;
1770   }
1771 }
1772
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));
1782   }
1783   pending_entries_->Append(entry);
1784 }
1785
1786 void NetInternalsMessageHandler::IOThreadImpl::PostPendingEntries() {
1787   DCHECK_CURRENTLY_ON(BrowserThread::IO);
1788   if (pending_entries_.get())
1789     SendJavascriptCommand("receivedLogEntries", pending_entries_.release());
1790 }
1791
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());
1798   }
1799   contexts.insert(io_thread_->globals()->proxy_script_fetcher_context.get());
1800   contexts.insert(io_thread_->globals()->system_request_context.get());
1801
1802   // Put together the list of all requests.
1803   std::vector<const net::URLRequest*> requests;
1804   for (std::set<net::URLRequestContext*>::const_iterator context =
1805            contexts.begin();
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);
1814     }
1815   }
1816
1817   // Sort by creation time.
1818   std::sort(requests.begin(), requests.end(), RequestCreatedBefore);
1819
1820   // Create fake events.
1821   for (std::vector<const net::URLRequest*>::const_iterator request_it =
1822            requests.begin();
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));
1827
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(),
1834                                       &callback);
1835     net::NetLog::Entry entry(&entry_data, request->net_log().GetLogLevel());
1836
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());
1841   }
1842 }
1843
1844 }  // namespace
1845
1846
1847 ////////////////////////////////////////////////////////////////////////////////
1848 //
1849 // NetInternalsUI
1850 //
1851 ////////////////////////////////////////////////////////////////////////////////
1852
1853 // static
1854 base::Value* NetInternalsUI::GetConstants() {
1855   base::DictionaryValue* constants_dict = net::NetLogLogger::GetConstants();
1856   DCHECK(constants_dict);
1857
1858   // Add a dictionary with the version of the client and its command line
1859   // arguments.
1860   {
1861     base::DictionaryValue* dict = new base::DictionaryValue();
1862
1863     chrome::VersionInfo version_info;
1864
1865     if (!version_info.is_valid()) {
1866       DLOG(ERROR) << "Unable to create chrome::VersionInfo";
1867     } else {
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" :
1876                                                        "unofficial");
1877       dict->SetString("os_type", version_info.OSType());
1878       dict->SetString("command_line",
1879                       CommandLine::ForCurrentProcess()->GetCommandLineString());
1880     }
1881
1882     constants_dict->Set("clientInfo", dict);
1883   }
1884
1885   return constants_dict;
1886 }
1887
1888 NetInternalsUI::NetInternalsUI(content::WebUI* web_ui)
1889     : WebUIController(web_ui) {
1890   web_ui->AddMessageHandler(new NetInternalsMessageHandler());
1891
1892   // Set up the chrome://net-internals/ source.
1893   Profile* profile = Profile::FromWebUI(web_ui);
1894   content::WebUIDataSource::Add(profile, CreateNetInternalsHTMLSource());
1895 }