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