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