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