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