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