• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
99 using base::StringValue;
100 using content::BrowserThread;
101 using content::WebContents;
102 using content::WebUIMessageHandler;
103 
104 namespace {
105 
106 // Delay between when an event occurs and when it is passed to the Javascript
107 // page.  All events that occur during this period are grouped together and
108 // sent to the page at once, which reduces context switching and CPU usage.
109 const int kNetLogEventDelayMilliseconds = 100;
110 
111 // Returns the HostCache for |context|'s primary HostResolver, or NULL if
112 // there is none.
GetHostResolverCache(net::URLRequestContext * context)113 net::HostCache* GetHostResolverCache(net::URLRequestContext* context) {
114   return context->host_resolver()->GetHostCache();
115 }
116 
HashesToBase64String(const net::HashValueVector & hashes)117 std::string HashesToBase64String(const net::HashValueVector& hashes) {
118   std::string str;
119   for (size_t i = 0; i != hashes.size(); ++i) {
120     if (i != 0)
121       str += ",";
122     str += hashes[i].ToString();
123   }
124   return str;
125 }
126 
Base64StringToHashes(const std::string & hashes_str,net::HashValueVector * hashes)127 bool Base64StringToHashes(const std::string& hashes_str,
128                           net::HashValueVector* hashes) {
129   hashes->clear();
130   std::vector<std::string> vector_hash_str;
131   base::SplitString(hashes_str, ',', &vector_hash_str);
132 
133   for (size_t i = 0; i != vector_hash_str.size(); ++i) {
134     std::string hash_str;
135     base::RemoveChars(vector_hash_str[i], " \t\r\n", &hash_str);
136     net::HashValue hash;
137     // Skip past unrecognized hash algos
138     // But return false on malformatted input
139     if (hash_str.empty())
140       return false;
141     if (hash_str.compare(0, 5, "sha1/") != 0 &&
142         hash_str.compare(0, 7, "sha256/") != 0) {
143       continue;
144     }
145     if (!hash.FromString(hash_str))
146       return false;
147     hashes->push_back(hash);
148   }
149   return true;
150 }
151 
152 // Returns a Value representing the state of a pre-existing URLRequest when
153 // net-internals was opened.
GetRequestStateAsValue(const net::URLRequest * request,net::NetLog::LogLevel log_level)154 base::Value* GetRequestStateAsValue(const net::URLRequest* request,
155                                     net::NetLog::LogLevel log_level) {
156   return request->GetStateAsValue();
157 }
158 
159 // Returns true if |request1| was created before |request2|.
RequestCreatedBefore(const net::URLRequest * request1,const net::URLRequest * request2)160 bool RequestCreatedBefore(const net::URLRequest* request1,
161                           const net::URLRequest* request2) {
162   return request1->creation_time() < request2->creation_time();
163 }
164 
165 // Returns the disk cache backend for |context| if there is one, or NULL.
GetDiskCacheBackend(net::URLRequestContext * context)166 disk_cache::Backend* GetDiskCacheBackend(net::URLRequestContext* context) {
167   if (!context->http_transaction_factory())
168     return NULL;
169 
170   net::HttpCache* http_cache = context->http_transaction_factory()->GetCache();
171   if (!http_cache)
172     return NULL;
173 
174   return http_cache->GetCurrentBackend();
175 }
176 
177 // Returns the http network session for |context| if there is one.
178 // Otherwise, returns NULL.
GetHttpNetworkSession(net::URLRequestContext * context)179 net::HttpNetworkSession* GetHttpNetworkSession(
180     net::URLRequestContext* context) {
181   if (!context->http_transaction_factory())
182     return NULL;
183 
184   return context->http_transaction_factory()->GetSession();
185 }
186 
ExperimentToValue(const ConnectionTester::Experiment & experiment)187 base::Value* ExperimentToValue(const ConnectionTester::Experiment& experiment) {
188   base::DictionaryValue* dict = new base::DictionaryValue();
189 
190   if (experiment.url.is_valid())
191     dict->SetString("url", experiment.url.spec());
192 
193   dict->SetString("proxy_settings_experiment",
194                   ConnectionTester::ProxySettingsExperimentDescription(
195                       experiment.proxy_settings_experiment));
196   dict->SetString("host_resolver_experiment",
197                   ConnectionTester::HostResolverExperimentDescription(
198                       experiment.host_resolver_experiment));
199   return dict;
200 }
201 
CreateNetInternalsHTMLSource()202 content::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?
222 class 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.
345 class 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 
GetMainContext()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 
NetInternalsMessageHandler()498 NetInternalsMessageHandler::NetInternalsMessageHandler() {}
499 
~NetInternalsMessageHandler()500 NetInternalsMessageHandler::~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 
RegisterMessages()509 void 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 
SendJavascriptCommand(const std::string & command,base::Value * arg)666 void 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 
OnRendererReady(const base::ListValue * list)682 void NetInternalsMessageHandler::OnRendererReady(const base::ListValue* list) {
683   IOThreadImpl::CallbackHelper(&IOThreadImpl::OnRendererReady, proxy_, list);
684 }
685 
OnClearBrowserCache(const base::ListValue * list)686 void 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 
OnGetPrerenderInfo(const base::ListValue * list)695 void 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 
OnGetHistoricNetworkStats(const base::ListValue * list)711 void 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 
OnGetExtensionInfo(const base::ListValue * list)719 void 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 
SystemLogsGetter(NetInternalsMessageHandler * handler,chromeos::system::SyslogsProvider * syslogs_provider)753 NetInternalsMessageHandler::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 
~SystemLogsGetter()764 NetInternalsMessageHandler::SystemLogsGetter::~SystemLogsGetter() {
765   DeleteSystemLogs();
766 }
767 
DeleteSystemLogs()768 void 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 
RequestSystemLog(const base::ListValue * args)777 void 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 
LoadSystemLogs()794 void 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 
OnSystemLogsLoaded(chromeos::system::LogDictionaryType * sys_info,std::string * ignored_content)807 void 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 
SendLogs(const SystemLogRequest & request)821 void 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 
IOThreadImpl(const base::WeakPtr<NetInternalsMessageHandler> & handler,IOThread * io_thread,net::URLRequestContextGetter * main_context_getter)847 NetInternalsMessageHandler::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 
~IOThreadImpl()859 NetInternalsMessageHandler::IOThreadImpl::~IOThreadImpl() {
860   DCHECK_CURRENTLY_ON(BrowserThread::UI);
861 }
862 
AddRequestContextGetter(net::URLRequestContextGetter * context_getter)863 void NetInternalsMessageHandler::IOThreadImpl::AddRequestContextGetter(
864     net::URLRequestContextGetter* context_getter) {
865   DCHECK_CURRENTLY_ON(BrowserThread::UI);
866   context_getters_.push_back(context_getter);
867 }
868 
CallbackHelper(MessageHandler method,scoped_refptr<IOThreadImpl> io_thread,const base::ListValue * list)869 void 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 
Detach()886 void 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 
OnWebUIDeleted()896 void NetInternalsMessageHandler::IOThreadImpl::OnWebUIDeleted() {
897   DCHECK_CURRENTLY_ON(BrowserThread::UI);
898   was_webui_deleted_ = true;
899 }
900 
OnRendererReady(const base::ListValue * list)901 void 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 
OnGetProxySettings(const base::ListValue * list)922 void 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 
OnReloadProxySettings(const base::ListValue * list)936 void 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 
OnGetBadProxies(const base::ListValue * list)945 void 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 
OnClearBadProxies(const base::ListValue * list)970 void 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 
OnGetHostResolverInfo(const base::ListValue * list)979 void 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 
OnClearHostResolverCache(const base::ListValue * list)1041 void 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 
OnEnableIPv6(const base::ListValue * list)1053 void 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 
OnStartConnectionTests(const base::ListValue * list)1064 void 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 
OnHSTSQuery(const base::ListValue * list)1081 void 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 
OnHSTSAdd(const base::ListValue * list)1159 void 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 
OnHSTSDelete(const base::ListValue * list)1194 void 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 
OnGetHttpCacheInfo(const base::ListValue * list)1211 void 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 
OnGetSocketPoolInfo(const base::ListValue * list)1234 void 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 
OnGetSessionNetworkStats(const base::ListValue * list)1247 void 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 
OnFlushSocketPools(const base::ListValue * list)1265 void 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 
OnCloseIdleSockets(const base::ListValue * list)1275 void 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 
OnGetSpdySessionInfo(const base::ListValue * list)1285 void 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 
OnGetSpdyStatus(const base::ListValue * list)1296 void 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 
1322 void
OnGetSpdyAlternateProtocolMappings(const base::ListValue * list)1323 NetInternalsMessageHandler::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 
OnGetQuicInfo(const base::ListValue * list)1345 void 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)
OnGetServiceProviders(const base::ListValue * list)1357 void 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)
OnRefreshSystemLogs(const base::ListValue * list)1399 void 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 
OnGetSystemLog(const base::ListValue * list)1407 void NetInternalsMessageHandler::OnGetSystemLog(
1408     const base::ListValue* list) {
1409   DCHECK(syslogs_getter_.get());
1410   syslogs_getter_->RequestSystemLog(list);
1411 }
1412 
ImportONCFileToNSSDB(const std::string & onc_blob,const std::string & passcode,net::NSSCertDatabase * nssdb)1413 void 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 
OnCertificatesImported(const std::string & previous_error,bool success,const net::CertificateList &)1455 void 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 
OnImportONCFile(const base::ListValue * list)1466 void 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 
OnStoreDebugLogs(const base::ListValue * list)1482 void 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 
OnStoreDebugLogsCompleted(const base::FilePath & log_path,bool succeeded)1499 void 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 
OnSetNetworkDebugMode(const base::ListValue * list)1510 void 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 
OnSetNetworkDebugModeCompleted(const std::string & subsystem,bool succeeded)1524 void 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 
OnSetLogLevel(const base::ListValue * list)1537 void 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.
OnAddEntry(const net::NetLog::Entry & entry)1555 void 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 
OnStartConnectionTestSuite()1562 void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTestSuite() {
1563   SendJavascriptCommand("receivedStartConnectionTestSuite", NULL);
1564 }
1565 
OnStartConnectionTestExperiment(const ConnectionTester::Experiment & experiment)1566 void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTestExperiment(
1567     const ConnectionTester::Experiment& experiment) {
1568   SendJavascriptCommand(
1569       "receivedStartConnectionTestExperiment",
1570       ExperimentToValue(experiment));
1571 }
1572 
1573 void
OnCompletedConnectionTestExperiment(const ConnectionTester::Experiment & experiment,int result)1574 NetInternalsMessageHandler::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 
1587 void
OnCompletedConnectionTestSuite()1588 NetInternalsMessageHandler::IOThreadImpl::OnCompletedConnectionTestSuite() {
1589   SendJavascriptCommand(
1590       "receivedCompletedConnectionTestSuite",
1591       NULL);
1592 }
1593 
1594 // Note that this can be called from ANY THREAD.
SendJavascriptCommand(const std::string & command,base::Value * arg)1595 void 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 
AddEntryToQueue(base::Value * entry)1617 void 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 
PostPendingEntries()1630 void NetInternalsMessageHandler::IOThreadImpl::PostPendingEntries() {
1631   DCHECK_CURRENTLY_ON(BrowserThread::IO);
1632   if (pending_entries_.get())
1633     SendJavascriptCommand("receivedLogEntries", pending_entries_.release());
1634 }
1635 
PrePopulateEventList()1636 void 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
GetConstants()1698 base::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 
NetInternalsUI(content::WebUI * web_ui)1732 NetInternalsUI::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