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