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